chenhg5/cc-connect · critical
target user %q can run passwordless sudo; isolation is meani
Error message
target user %q can run passwordless sudo; isolation is meaningless. Remove NOPASSWD sudo for this user. Output: %s
What it means
VerifyRunAsUserCheap (core/runas.go:249) refuses to start an isolated session when the target run-as user can itself run passwordless sudo ('sudo -n /usr/bin/true' succeeds as that user). If the sandboxed user can escalate to root, the isolation is theater, so startup fails closed with a remediation hint.
Source
Thrown at core/runas.go:249
//
// The expensive checks (work_dir access, isolation probe) live in the
// preflight and audit packages and only run at startup / via `cc-connect
// doctor user-isolation`.
func VerifyRunAsUserCheap(ctx context.Context, runner SudoRunner, runAsUser string) error {
if runAsUser == "" {
return errors.New("VerifyRunAsUserCheap: runAsUser is empty")
}
if verifyCacheHit(runAsUser) {
return nil
}
if out, err := runner.Run(ctx, "-n", "-iu", runAsUser, "--", "/usr/bin/true"); err != nil {
verifyCacheEvict(runAsUser)
return fmt.Errorf("passwordless sudo to user %q failed (check that your sudoers rule is present and scoped to this user): %w: %s", runAsUser, err, strings.TrimSpace(string(out)))
}
out, err := runner.Run(ctx, "-n", "-iu", runAsUser, "--", "sudo", "-n", "/usr/bin/true")
if err == nil {
verifyCacheEvict(runAsUser)
return fmt.Errorf("target user %q can run passwordless sudo; isolation is meaningless. Remove NOPASSWD sudo for this user. Output: %s", runAsUser, strings.TrimSpace(string(out)))
}
verifyCacheStore(runAsUser)
return nil
}
// verifyCacheTTL is short by design. It absorbs a burst of messages
// (one Slack user typing rapidly) while still re-verifying often enough
// that a sudoers edit during a long idle gap is caught on the next spawn.
const verifyCacheTTL = 30 * time.Second
var (
verifyCacheMu sync.Mutex
verifyCache = map[string]time.Time{}
)
func verifyCacheHit(user string) bool {
verifyCacheMu.Lock()
defer verifyCacheMu.Unlock()View on GitHub (pinned to 4000b2338a)
Solutions
- Remove NOPASSWD sudo privileges from the target user: delete or narrow the offending /etc/sudoers.d entry
- Ensure the target user is not in the sudo/wheel group (gpasswd -d <target> sudo)
- Scope remaining sudoers rules to the specific supervisor→target direction only, never ALL
- Verify with: sudo -n -iu <target> -- sudo -n /usr/bin/true — this must now fail
- Restart cc-connect so verification re-runs and the cache refreshes
Example fix
// before: /etc/sudoers.d/agent agentuser ALL=(ALL) NOPASSWD: ALL // after: no sudo for the target; only supervisor may act as agentuser supervisor ALL=(agentuser) NOPASSWD: ALL
Defensive patterns
Strategy: validation
Validate before calling
func targetCanEscalate(target string) bool {
return exec.Command("sudo", "-n", "-iu", target, "--", "sudo", "-n", "/usr/bin/true").Run() == nil
}
// must be false before enabling run-as isolation Try / catch
sess, err := newClaudeSession(ctx, cfg)
if err != nil {
if strings.Contains(err.Error(), "can run passwordless sudo") {
log.Fatalf("Security: %v — strip NOPASSWD sudo from the target user and retry", err)
}
return err
} Prevention
- Never grant NOPASSWD ALL to service/agent users; scope sudoers to supervisor→target only
- Exclude agent users from sudo/wheel groups in provisioning
- Add a deployment check that the target user cannot sudo (this probe) and fail the deploy otherwise
- Audit /etc/sudoers.d/ periodically for overly broad rules
When it happens
Trigger: Called from newClaudeSession when the second probe, run AS the target user, succeeds — meaning the sudoers setup granted the target user NOPASSWD sudo (e.g. an overly broad 'agentuser ALL=(ALL) NOPASSWD: ALL' rule, or membership in a sudo group with NOPASSWD).
Common situations: Admin lazily granted the agent user full sudo instead of scoping it; the target user is in the wheel/sudo group with NOPASSWD set globally; a base image or provisioning script added broad sudoers rules for service users.
Understand the failure class
Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.
Related errors
- project %q: target user %q can run passwordless sudo. The ru
- VerifyRunAsUserCheap: runAsUser is empty
- RunIsolationProbe: RunAsUser is empty
- PreflightRunAsUser: RunAsUser is empty
- run_as_user is not supported on Windows
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/e31e49ed439cd676.
Report an issue: GitHub.