Skip to content

fix(signer): let a confined AppContainer signer read its sealed key on Windows#417

Open
ion-alpha-dev wants to merge 3 commits into
mainfrom
fix/windows-signer-sealed-key-appcontainer-read
Open

fix(signer): let a confined AppContainer signer read its sealed key on Windows#417
ion-alpha-dev wants to merge 3 commits into
mainfrom
fix/windows-signer-sealed-key-appcontainer-read

Conversation

@ion-alpha-dev

Copy link
Copy Markdown
Collaborator

What

Grant a signer extension's sealed key to ALL APPLICATION PACKAGES before the signer process launches, so the confined signer can open the key the host named for it. The grant is read on the key file and traverse on the two directories above it, non-inheritable, and it is a no-op off Windows. Adds sandbox.GrantSealedKeyReadable, called from mountSigner right after the key is located and before the launch, plus tests that assert the entry lands on the file and its parents and that repeated grants are idempotent.

Why

A signer runs confined, and on Windows that is an AppContainer with a default-deny filesystem. The host seals a key at <data-dir>/signers/<name>.key and hands the path to the signer over the private unlock channel, but nothing granted the container read on that file, so the signer failed at unlock with read sealed key: Access is denied and a mint never reached signing. The container's package SID is minted fresh from the scratch working directory on every launch, so granting the per-launch SID would leave a dead entry by the next run; the well-known ALL APPLICATION PACKAGES SID is stable and carried by every AppContainer. Granting it here is safe because the file is an encrypted box whose passphrase lives only in the vault and never touches disk, so a package-read entry on the ciphertext discloses nothing to a container that does not already hold the passphrase. The grants are scoped tightly (read on the one key file, traverse-only on the parents) so no other file under the data directory is exposed.

How to verify

On Windows, seal a Solana key and run a signed mint through the released signer:
flynn auth set signer/solana-signer, seal a raw key to %APPDATA%\flynn\signers\solana-signer.key, then flynn extensions call token token_mint '{"name":"T","symbol":"T","metadataUri":"https://example.com/t.json","supply":1000000}' --signer solana-signer --endpoint https://api.devnet.solana.com. Before this change the call fails at unlock with Access is denied; after it, the signer unlocks, signs, and the mint lands a fixed-supply token with its mint authority revoked. go test ./sandbox/ -run GrantSealedKey covers the ACL entry and idempotency on Windows and the no-op off Windows.

…n Windows

A signer extension runs confined, and on Windows that is an AppContainer with a
default-deny filesystem. The host names a sealed key at <data-dir>/signers/<name>.key
and hands the path to the signer at unlock, but nothing granted the container read on
that file, so the signer failed at unlock with "read sealed key: Access is denied" and
the mint never reached signing. The container's package SID is also minted fresh from
the scratch working directory on every launch, so granting the per-launch SID would
leave a dead entry by the next run.

Grant the sealed key to ALL APPLICATION PACKAGES before the signer launches: read on
the key file and traverse on the two directories above it, non-inheritable so nothing
else under the data directory is exposed. The key is an encrypted box whose passphrase
lives only in the vault and reaches the signer over the private unlock channel, never
on disk, so a package-read entry on the ciphertext discloses nothing to a container
that does not already hold the passphrase. Off Windows the grant is a no-op: a signer
there reads the key through ordinary POSIX permissions.

Verified end to end on devnet: a stock-path signed mint through the released
solana-signer now unlocks, signs, and lands a fixed-supply token (authority revoked).
@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

The sealed-key grant test asserted the entry landed by string-matching the security
descriptor's SDDL, but a well-known SID renders as its alias there (ALL APPLICATION
PACKAGES prints as "AC", not "S-1-15-2-1"), so the match failed on some Windows builds.
Walk the access list and compare the trustee SID by value instead. Also range over the
integer bounds so the loops satisfy the intrange linter.
…me seam

The grant that makes a signer's sealed key reachable by its confined process can only
fail on Windows, so the mount's error branch for it had no coverage on the platforms CI
measures. Route the grant through a field on the extension runtime, defaulted to the
real grant, so a test can inject a failure and assert the mount aborts naming that
reason. No behaviour change: production still calls the platform grant.
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