Skip to content

[Security] Reject symlink and special-file Agent Artifact Admission inputs #254

Closed

Description

@seonghobae

Finding

Agent Artifact Admission exact c4030f7fecaa5627ccec31ce58eca7e59db45334 opens both the reviewed policy configuration and protected credential document with File::open(path) and only then validates permissions on the resulting descriptor. The same-descriptor metadata check correctly closes the earlier pathname-metadata TOCTOU interval, but File::open still follows a final symbolic link and can block while opening a FIFO before Wardnet gets a chance to validate file type.

This is Wardnet-owned local admission-policy / credential bootstrap authority. It does not move effective runtime environment/config ownership out of quarantine-sandbox-runtime and does not duplicate EgressWeave, contextual-orchestrator or AppGuardrail behavior.

The existing audit sink already establishes the intended Linux pattern: O_NOFOLLOW | O_NONBLOCK, followed by regular-file validation on the same opened descriptor. Configuration and credential readers have not yet adopted that pattern.

Hostile RED acceptance

Against production source byte-identical to exact #129 head:

  • a mode-0600 credential target reached only through a final symlink must fail closed rather than return the bearer token;
  • a safe-permission reviewed policy target reached only through a final symlink must fail closed rather than load policy authority;
  • a no-writer FIFO must not be allowed to block startup before file-type validation; the reader must open nonblocking and reject non-regular files;
  • ordinary owner-only credential files and integrity-protected regular policy files remain accepted.

A symlink-only test is sufficient to establish the first semantic RED without creating an unbounded test; FIFO behavior should be added to the GREEN acceptance once the nonblocking open boundary exists.

Minimum causal repair

Use one Linux read-only open with O_NOFOLLOW | O_NONBLOCK, then validate regular-file type and the existing permission invariant on that same descriptor before materializing bounded bytes. Keep the current explicit fail-closed behavior on platforms where an equivalent native contract is not implemented. Do not add pathname pre-checks followed by a second open, because that would recreate a TOCTOU interval.

Traceability

  • Linux/POSIX open: O_NOFOLLOW rejects a final symbolic link; O_NONBLOCK prevents FIFO read-open from waiting for a writer.
  • MITRE CWE-59 / CWE-61: link following can resolve a security-sensitive pathname outside the intended control sphere.

Close only after the hostile regression, causal repair, exact-head CI/fuzz/security evidence and complete transfer into #129 or a verified successor are present. No force update, destructive rebase, gate weakening, self/model approval or predecessor-evidence reuse.

Activity

  1. seonghobae commented on Sep 10, 2026

    @seonghobae
    ContributorAuthor

    Verified successor carry-forward is now complete on the canonical Agent Artifact Admission lineage.

    Child #255 exact source df64d5f87588ba094793d5f52569b191673b9dc1 preserved the hosted hostile RED dcfa3ace0b5d83bbc4fd5f5d76fbf22008a6c6e4 for final-symlink/config credential authority plus the real FIFO no-reader case, and repaired the acquisition boundary with Linux O_NOFOLLOW | O_NONBLOCK, same-descriptor regular-file/permission validation, bounded read, and non-Linux fail-closed behavior. Its exact CI 34453941622 and Fuzz 34453941689 were terminal SUCCESS with zero review threads.

    #255 was then ordinarily merged with expected head into canonical #129 as eec36424a2a4cd3e08e6ab61af1e112e387f2ac4; no force update, destructive rebase, bypass, or self/model approval was used. Fresh current-successor execution on unchanged eec36424... is now CI 34455679293 SUCCESS, Fuzz 34455679180 SUCCESS, Security Scan 34455679242 SUCCESS, and SAST Semgrep 34455679327 SUCCESS. Fresh #129 inline review inventory has zero unresolved threads. The remaining CodeQL PR failure is the independently reproduced central delegated-verdict settlement defect handed to .github#1929; it does not invalidate or replace this narrow Wardnet file-authority repair.

    Issue acceptance is therefore satisfied by verified successor transfer of the full hostile test, causal production delta and exact evidence. #128 remains open until the canonical #129 lineage itself reaches protected main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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