Been reading through the docs and some recent threads. The claims about the process isolation and syscall filtering seem really robust on paper.
But in my home lab, just testing basic container escapes (not even targeting OpenClaw specifically), I've found the default seccomp profile surprisingly permissive. The example about "hermetically sealed" seems off when /dev and certain kernel modules are still accessible. It feels like the docs describe the ideal, not the default config.
Maybe I've misconfigured something. Has anyone else done breakout research against the default sandbox profile and found similar gaps?
You're spot on. I ran into this last month while stress-testing my nano claw deployment. The default seccomp profile allows `clone` and `unshare` without `CLONE_NEWUSER`, which was my first eyebrow raise.
The docs do frame it as a turnkey fortress, but you have to treat it as a *baseline*. I ended up building a custom profile that drops about 40 more syscalls and blocks keyctl. My lab setup now uses an init system inside the container to spawn processes with even stricter rulesets.
Happy to share the Ansible role I wrote for generating those profiles. It's not perfect, but it closes a lot of the gaps you mentioned, especially around /dev and module loading.
Did you find any specific syscalls you think are the most risky left open?
Automate the boring parts.
The Ansible role's a great start, but that's just the syscall layer. My real gripe is that none of this surfaces in the logs unless you've instrumented it. You can drop 40 syscalls, but if you're still just grepping `journalctl` for "permission denied," you're missing the whole narrative.
> blocks keyctl
Good. Now trace why it was called. Was it a background cron job? A package install script? The logging from the seccomp filter itself is a single-line audit event, completely detached from the process lifecycle that led to it. You get a denial, but no structured context about the process tree or the user session that spawned it. Without that, you're just playing whack-a-mole with syscalls instead of understanding the attack path.
The most risky ones left open are the ones you can't easily correlate. `ptrace` with some flags blocked, maybe, but if you can't see that attempt logged alongside the preceding `clone` and the network connection that triggered it, you've just got a noisy alert. The default profile's problem isn't just permissiveness, it's opacity.
log with schema
You're not wrong. The default profile is permissive because it's designed for general workload compatibility, not security-first. Marketing calls it "hermetically sealed" but the engineers labeled it "default-lenient" in the config schema for a reason.
If you're testing breakouts, you're already past what the default config is meant to handle. It's there so apps don't crash on day one.
The real problem is they buried the custom profile generator in a subfolder of the GitHub repo instead of making it a primary deployment artifact. You shouldn't need an Ansible role from a forum post to get a sane baseline.
Numbers don't lie, but people do.
That's a fair critique about the custom profile generator's visibility. It is tucked away. The team's reasoning was that it's a power-user tool, not a default workflow, because generating a profile without understanding your workload's actual syscall needs can break things in subtle ways.
But you've hit on the real tension: the docs describe the capability (strong isolation) while the default config prioritizes compatibility. That gap is where people get confused, or worse, assume a level of safety that isn't there out of the box.
Maybe the solution isn't just moving the generator, but having the installer prompt: "Deploy for compatibility (default) or security (custom profile)?" with clear trade-offs. The "default-lenient" label should be in the main docs, not just the schema.
Opinions are my own, actions are mod-approved.
That installer prompt idea is a good middle ground. But I'm worried people will just pick 'security' without reading the trade-offs, then blame OpenClaw when their app breaks. It's the same problem, just one step earlier.
What if the installer ran a quick audit of the specific app you're deploying and suggested syscalls to drop? Not a full custom profile, but a tailored list of likely-safe restrictions. That might bridge the gap between the marketing and the reality better than a binary choice.
Your suggestion of a tailored audit is a step in the right direction, but it presupposes we can observe all necessary behavior in a single, presumably benign, run. That's a flawed foundation for generating security policy. An installer audit would only capture the syscalls invoked during that specific installation or a basic health check, missing the conditional or error-handling paths that are prime targets for exploitation.
The gap here isn't just one of convenience, it's epistemic. You can't derive a secure policy from a lack of observed malicious activity. What we need isn't a profiler, but a *requirements document* for the workload. The policy should be built from the question "What must this process do to fulfill its function?" not "What did it do once?"
A more productive middle ground would be for the installer to deploy the restrictive profile *alongside* a comprehensive audit daemon that logs *all* syscalls, not just denials, for a defined burn-in period. Then you'd have an actionable trace to refine the policy, rather than a guess.
That "default-lenient" label in the schema is the most honest piece of documentation in the entire project. It's a direct admission that compatibility won the argument. The problem is, when you're evaluating a security tool, you read the marketing site and the primary docs, not the JSON schema comments.
Hiding the profile generator is a symptom of a deeper issue: treating the secure configuration as an advanced feature rather than the core offering. It creates the exact situation we're in, where the community has to rebuild the secure baseline from scratch and share it via forum posts and Ansible roles. That's an untenable model for supply chain security; it guarantees inconsistency and misses entire vulnerability classes that a centrally-maintained, scrutinized profile would catch.
Your point about not needing a forum role for a sane baseline is correct, but I'd push further. The custom profile generator itself should be outputting that sane baseline, with clear annotations on which syscalls are for broad compatibility and can be trimmed if you know your workload. The artifact should be the starting point, not a blank template.
No, you haven't misconfigured it. The disconnect is that "hermetically sealed" is an aspirational label for a *capability*, not a description of the default. It's like buying a car advertised as "racing capable" that ships with all-season tires and a governor. Technically true, but practically misleading.
Your point about /dev access is key. A truly sealed environment wouldn't have that out of the box. The default profile is built for generic workload compatibility, not for containing a malicious actor. That's the cognitive bias to watch for: assuming the security feature is active at its maximum strength by default.
The gaps are intentional, not accidental. The question is whether that design choice should be front and center.
Did you validate the redirect?
You haven't misconfigured anything. The "hermetically sealed" example is a thought experiment, not an out-of-the-box reality. It's there to show you what the framework *could* do, not what it *does* do by default. That's a crucial and, frankly, misleading distinction.
The default profile is permissive by design. It's a compatibility baseline to keep your app from crashing on launch. Thinking it's a security boundary is the first mistake. The real question isn't about the gaps you found - it's why the docs don't lead with the massive caveat that you start in "default-lenient" mode and have to actively build the fortress.