Repository navigation
fix(security): write the token cache owner-only (GHSA-prmg-4fr3-mm6x) - #167
Merged
Merged
Conversation
The cache holding the long-lived Meta access token was created by a bare open(path, 'w') inside a directory made by mkdir() with no mode, so under the usual 0022 umask it landed at 0644 inside 0755 — readable by every other local user on a shared host. The file is now created with os.open(..., O_CREAT, 0o600) and the directory with mode 0o700. O_CREAT's mode only applies at creation and mkdir's is masked by the umask, so both are narrowed explicitly afterwards; the same narrowing runs on load, which repairs a cache written by an earlier version without requiring re-authentication. The chmod step is skipped on Windows, where access is governed by ACLs. Bumps to 1.0.127 and documents the advisory in SECURITY.md.
PM-Labs
pushed a commit
to pmlabs-org/mcp-meta-ads
that referenced
this pull request
Oct 11, 2026
…pipeboard-co#167) The cache holding the long-lived Meta access token was created by a bare open(path, 'w') inside a directory made by mkdir() with no mode, so under the usual 0022 umask it landed at 0644 inside 0755 — readable by every other local user on a shared host. The file is now created with os.open(..., O_CREAT, 0o600) and the directory with mode 0o700. O_CREAT's mode only applies at creation and mkdir's is masked by the umask, so both are narrowed explicitly afterwards; the same narrowing runs on load, which repairs a cache written by an earlier version without requiring re-authentication. The chmod step is skipped on Windows, where access is governed by ACLs. Bumps to 1.0.127 and documents the advisory in SECURITY.md.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes GHSA-prmg-4fr3-mm6x, reported by @Gal3m and @mohammad228.
The bug
The cache holding the long-lived Meta access token (~60 days) was created by a bare
open(path, "w"), inside a directory made bymkdir()with no mode. Reproduced on this machine with the old code path:On a shared host — CI runner, bastion, multi-UID container — any other local user could read the operator's credential and act as them against the Graph API.
The report also names
pipeboard_token_cache.jsoninpipeboard_auth.py. That module was deleted in 1.0.121, so there is nothing left to fix there;token_cache.jsonwas the only remaining credential file written by the package (grepfor otheropen(..., "w")writes finds none).The fix
os.open(path, O_WRONLY|O_CREAT|O_TRUNC, 0o600)and the directory withmkdir(mode=0o700).O_CREAT's mode applies only when the file is created andmkdir's mode is masked by the umask and is a no-op for a directory that already exists. This is also what repairs a cache written by an earlier version._restrict_permissionsis best-effort and never raises into the caller, and it is skipped on Windows, where chmod cannot express "owner only" and access is governed by ACLs.The fd handling is written so the descriptor is closed exactly once: if
os.fdopenfails the raw fd is closed, otherwise the file object owns it.Tests
tests/test_token_cache_permissions.py— 7 cases: file and directory modes, that the modes hold underumask(0o000)(the umask is what produced 0644, so it is what the fix has to survive), that a pre-existing 0644 cache is narrowed on both save and load, that the owner can still read what was written, and that a vanished path does not raise.Full suite: 604 passed, 9 skipped. Bumped to 1.0.127 with a SECURITY.md entry that tells operators on shared hosts to rotate the token.