Skip to content

chore(hardening): extend private-address blocking and verify downloaded artifacts - #1

Merged
devGregA merged 1 commit into
mainfrom
hardening/network-artifact-integrity
Aug 13, 2026
Merged

chore(hardening): extend private-address blocking and verify downloaded artifacts#1
devGregA merged 1 commit into
mainfrom
hardening/network-artifact-integrity

Conversation

@devGregA

Copy link
Copy Markdown
Contributor

Problem

Two defence-in-depth gaps in this fork's baseline (v0.34.0):

  1. The URL-fetch private-address blocklist covers IPv4 ranges and their IPv4-mapped IPv6 forms, but not NAT64 (RFC 6052), which carries an IPv4 address in the low 32 bits of 64:ff9b::/96. Those are ordinary IPv6 addresses, so on a NAT64 network a request to 64:ff9b::<private v4> translates straight through to the embedded target.
  2. The capability downloader wrote whatever the server returned straight to disk with no integrity check, and the macOS computer-use bundle then had its quarantine attribute stripped, so Gatekeeper never evaluated it.

What changed

Address blocking (both engine copies — agent-core and agent-core-v2):

  • Each private IPv4 subnet is now mirrored into NAT64 space (96 + <v4 prefix bits>), derived from a single list rather than duplicated literals.
  • The RFC 8215 local-use prefix 64:ff9b:1::/48 has no fixed embedding offset, so it is blocked wholesale.
  • Public IPv4 addresses reached over NAT64 are deliberately still allowed — this narrows reachability without breaking IPv6-only networks. Covered by a regression test.

Artifact integrity (agent-core-v2 capability host):

  • downloadToFile takes an optional expectedSha256, computed while streaming (no re-read). On mismatch the partial file is removed before throwing, so an unverified artifact is never left where a later step could execute it. Backwards compatible: unset means today's behaviour.
  • The xattr -dr com.apple.quarantine call on the downloaded .app is removed. The bundle is fetched over the network and is not checked against a published digest, so Gatekeeper stays the backstop.

Testing

  • New cases in the SSRF-guard suites of both engines (NAT64 literals, NAT64 via DNS, and a no-regression case proving public-v4-over-NAT64 still fetches).
  • New downloadToFile cases: matching digest is kept, mismatching digest throws and leaves nothing on disk.
  • Verified as real tests, not tautologies: with the source changes reverted the three new negative tests fail; with them applied all 94 tests in the affected suites pass.
  • oxlint clean on changed files; tsc --noEmit clean for both packages.

Checklist

  • Problem explained above (fork-local hardening; no upstream issue).
  • Tests added that prove the change works.
  • Changeset added (patch for both packages).
  • No doc update needed.

…ed artifacts

Mirror each private IPv4 range into the NAT64 well-known prefix
(RFC 6052 64:ff9b::/96) so a NAT64 network cannot be used to reach a
private v4 target through an IPv6 literal, and block the RFC 8215
local-use prefix wholesale. Public IPv4 addresses reached over NAT64
stay allowed. Applied to both engine copies of the fetch provider.

Give the capability downloader an optional expectedSha256: the digest is
computed while streaming and a mismatch removes the file before throwing,
so an unverified artifact is never left on disk for a later step to run.

Leave the quarantine attribute on the downloaded macOS bundle in place so
Gatekeeper still evaluates it on first launch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@devGregA
devGregA merged commit 4d03c96 into main Aug 13, 2026
23 of 24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant