Skip to content

filesystem.allowWrite silently disables token protection and the gh proxy wrapper #7681

Description

@lpcox

Follow-up to #7678 / #7679. Those fixed every path that broke agent startup under filesystem.allowWrite. Two AWF-internal writes under /tmp remain. Neither stops the container from starting, so the live integration test passes, but one silently weakens security.

1. /tmp/awf-lib — token protection and the gh proxy wrapper degrade silently

containers/agent/entrypoint.sh stages three things into /host/tmp/awf-lib for use inside the chroot:

  • one-shot-token.so (LD_PRELOAD token protection)
  • the Claude CLAUDE_CODE_API_KEY_HELPER
  • gh-cli-proxy-wrapper.sh, prepended to PATH as /tmp/awf-lib/gh

filesystem.allowWrite narrows the /tmp bind to read-only, so these writes fail. The code degrades gracefully instead of failing, which is why nothing is red. Observed directly in run 32681985728 with allowWrite: ["<tmpdir>/agent"]:

[entrypoint][WARN] Could not copy one-shot-token library to /tmp/awf-lib
[entrypoint][WARN] Token protection will be disabled (tokens may be readable multiple times)

So enabling filesystem.allowWrite currently disables one-shot token protection and the gh CLI proxy wrapper, with only a warning. That is a security regression triggered by opting into a security feature.

The comment at entrypoint.sh:642 still claims /tmp/awf-lib/ is "always writable", which is no longer true.

Suggested fix: relocate to /run/awf-lib, matching /run/awf-init (#7679) and /run/awf-cmd-$$.sh (0cb81ea). /run inside the chroot is the container's own writable rootfs, not a host bind, so it is unaffected by any host write policy. ~49 literal references in entrypoint.sh.

Worth confirming /run is not mounted noexec in any supported topology before relying on it for the LD_PRELOAD .so and the gh wrapper — the command-script move only proves it is writable and readable.

2. /tmp/awf-runner-bin — ARC/DinD staging mount

src/services/agent-volumes/workspace-mounts.ts:52 mounts the staged runner binary at /tmp/awf-runner-bin/<name>, nested under the narrowable /tmp bind. stageHostFile writes to the AWF work dir, not to /tmp/awf-runner-bin, so the mountpoint does not exist on the host and runc cannot create it under a read-only parent.

Only reachable with --docker-host-path-prefix (ARC/DinD split filesystem) and filesystem.allowWrite, so it did not surface in CI. gh-aw uses both, so the intersection is realistic.

/tmp/awf-runner-bin is baked into entrypoint.sh in ~9 places including PATH construction and error text, so this is an image-contract change and should ship in lockstep with a release.

Suggested checklist

  • Move /tmp/awf-lib to /run/awf-lib
  • Verify /run is not noexec for the LD_PRELOAD .so and the gh wrapper
  • Fix the stale "always writable" comment at entrypoint.sh:642
  • Decide on /tmp/awf-runner-bin (move, or pre-create the host mountpoint)
  • Extend the ARC/DinD integration coverage to run with a filesystem.allowWrite policy
  • Add an assertion that token protection stays enabled under allowWrite, so this cannot regress silently again

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions