Skip to content

#820's alias-ownership fix is merged but not deployed — GHSA-q9qq-223w-mqx6 is still live #859

Closed

Description

@scttfrdmn

PR #836 closed #820 and the advisory was published. The fix is not running in production.

spawn-dns-updater's LastModified is 2026-06-25T06:20:28. PR #836 merged in October. Confirmed against the deployed bytes rather than inferred from the date — downloaded via get-function's Code.Location and grepped the binary:

ABSENT  : _spore-owner
ABSENT  : aliasSubdomainOwner
ABSENT  : authorizeCaller
ABSENT  : DNS_AUTHZ_MODE
ABSENT  : must be an IPv4 literal
PRESENT : aliasDNSName

aliasDNSName being present is the control: it proves the grep works on this binary and that the absences are real, not an invocation artefact. The deployed function therefore still builds the friendly alias from req.AccountName with no ownership check, which is GHSA-q9qq-223w-mqx6 exactly: any caller can UPSERT or DELETE {record}.{any-other-tenant-slug}.spore.host.

The ip_address validation from #835 is likewise not deployed.

Why it wasn't deployed

scripts/deploy-custom-dns.sh was unsafe to run until PR #858, which is the direct cause of the four-month gap. It granted IAM to SpawnDNSLambdaRole (a role that does not exist — the function runs under SpawnDNSLambdaExecutionRole), and its update path passed --environment Variables={...}, which would have deleted DOMAIN_ZONES, the only variable the live function has. Both fixed in #858.

What needs doing

  • Deploy spawn-dns-updater from main once Authorize DNS-updater callers against the account registry (#835) #858 lands, with the fixed script.
  • Verify the deployed bytes, not the API's 200: re-run the grep above and expect _spore-owner and aliasSubdomainOwner PRESENT.
  • Confirm DOMAIN_ZONES survives the deploy (get-function-configuration --query 'Environment.Variables' before and after; expect zero drift plus whatever is deliberately added).
  • Check whether the live _spore-owner markers need seeding for the two existing alias tenants, or whether first-caller-claims is acceptable for them.

The general problem

This is the "merged != deployed" gap for the hand-deployed Lambdas, and nothing warns. The reaper stack sat untouched 2026-07-31 to 2026-10-04 while the CLI went v0.9x to v0.116.0. A published advisory whose fix is in main but not in production is the worst case of it, because the advisory asserts the fix shipped.

Worth considering: a check that compares each deploy script's target function's CodeSha256 against a locally-built zip (deploy-sweep-orchestrator.sh already does this for itself), run as a census rather than per-deploy.

Activity

  1. scttfrdmn commented on Oct 12, 2026

    @scttfrdmn
    ContributorAuthor

    Deployed and verified. GHSA-q9qq-223w-mqx6 is remediated in production.

    • Deploy spawn-dns-updater from main with the fixed script. LastModified 2026-06-25 → 2026-10-12T16:32:59Z; CodeSha256 OmdRFNPs… → 4ms+TCaL….

    • Verify the deployed bytes, not the API's 200. Re-ran the grep from this issue against the newly downloaded artifact, this time with literals first confirmed to be real string literals in source (not comment text — that mistake produced a false "absent" earlier today), plus a negative control:

      PRESENT : _spore-owner
      PRESENT : must be an IPv4 literal
      PRESENT : is not registered in
      PRESENT : zone %s returned no records at all
      ABSENT  : <sentinel>   (so the grep discriminates)
      

      _spore-owner is the alias-ownership marker, so Resolve the DNS alias owner server-side instead of from the request body #820's fix is live.

    • Confirm DOMAIN_ZONES survives. It does — this is the Authorize DNS-updater callers against the account registry (#835) #858 merge-not-replace fix working on its first real use. Before: {DOMAIN_ZONES: spore.host=Z0341053304H0DQXF6U4X}. After: that value unchanged, plus DEFAULT_DOMAIN, HOSTED_ZONE_ID, DNS_ALLOWED_ACCOUNTS, DNS_ACCOUNTS_TABLE. Under the old script this deploy would have deleted DOMAIN_ZONES.

    • Check whether _spore-owner markers need seeding. They don't. mycelium-development still has its two CNAMEs pointing at *.5k0zfnmq.spore.host, so aliasSubdomainOwner infers the owner as 435415984226 from the zone's own state, exactly as designed, and first-caller-claims will record the marker on the next write. No manual seeding.

    Also: runtime provided.al2023 and arch x86_64 unchanged (the script builds GOARCH=amd64, checked against the live arch before deploying — an arm64 build would have been an exec-format failure), log retention set to 30 days, and spawn:version=0.127.0-34-g5610712 stamped.

    One regression I introduced and reversed

    Running the script executed its Step 5/6, which I had not audited when fixing the script in #858. It created a REST API spawn-dns-api (tcdwlpysn2) with POST /update-dns at authorizationType: NONE and added an apigateway-invoke statement to the function's resource policy — a public, unauthenticated endpoint into the DNS updater, created at 16:33Z.

    It could not write DNS: a probe returned 502, because the handler takes a Function URL event (LambdaFunctionURLRequest) and API Gateway REST sends a different shape, so the integration is incompatible. The zone stayed at 17 records. But it was still an unauthenticated public invoke path on a billable function.

    Both are gone — API deleted, statement removed, resource policy back to its pre-deploy shape and then narrowed per #835. Nothing depended on it: both /spawn/dns/* SSM parameters are absent, and spored uses the Function URL (…lambda-url.us-east-1.on.aws, AWS_IAM).

    Filed as #870, because the script will recreate it for the next person.

    Noted, not actioned

    The function carries a managedby: opentofu tag alongside spawn:created-by: deploy-custom-dns.sh. If there is live OpenTofu state for this function, a script deploy puts it in drift. Worth confirming which tool is meant to own it.

    Closing — the advisory's fix is now actually running.

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

    area:networkingVPC / security groups / DNSbugSomething isn't working

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions