T09 · Insecure Skill Coding Practices
- Location
SKILL.md:59- Finding
Long-Lived Bearer Token Stored in a Predictable Plaintext File
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 59–60 and 89–91
Vulnerability Type: Plaintext storage of sensitive authentication credentials
Risk Level: MediumVulnerable Code Snippet
markdown **Credential storage convention (reused across conversations)**: - This skill persists its token in the Agent's local file **`~/.gts-operator.json`** (JSON: `{"token": "<jwt>", "saved_at": <unix>, "tenant_id": <int>, "user": {...}}`).markdown - `data.status == "authorized"` → Success! `data.token` is a **30-day token**. Write the token to `~/.gts-operator.json`.The same storage design is documented in
README.md, lines 78–80.Technical Analysis
The Skill directs the Agent to persist a bearer token with a 30-day lifetime in a predictable plaintext file in the user's home directory. The instructions do not require:
- Owner-only permissions such as mode
0600 - Verification of file ownership or permissions before reading
- Protection against symbolic-link attacks
- Atomic, race-resistant file creation
- Encryption through an operating-system credential store
- Minimization of additional identity and tenant metadata
A bearer token provides access based solely on possession. Any local user, process, malicious extension, or compromised Skill that can read this file can reuse the token without knowing the account password. Persisting it across conversations increases the exposure period.
This is credential persistence for the Skill's legitimate authentication function rather than a system-persistence backdoor. It is therefore classified as insecure sensitive-data storage.
Attack Path
- A user completes the documented OAuth device authorization.
- The Agent receives a bearer token valid for 30 days.
- Following the Skill instructions, the Agent writes that token in plaintext to
~/.gts-operator.json. - A malicious local process or another user wit ...[truncated 1406 chars]
- Owner-only permissions such as mode
- Remediation
View remediation
Remediation Suggestions
- Store the bearer token in the operating system's credential manager, such as Keychain, Credential Manager, or Secret Service, rather than in a plaintext JSON file.
- If file storage is unavoidable:
- Create the file atomically with owner-only mode
0600. - Ensure the containing directory is not writable by other users.
- Reject symbolic links and use no-follow semantics where supported.
- Verify the file is a regular file owned by the expected user before every read.
- Refuse to use files with group or world permissions.
- Write through a securely created temporary file and atomically rename it.
- Create the file atomically with owner-only mode
- Store only the token and essential expiry metadata. Avoid persisting unnecessary user and tenant details.
- Reduce token lifetime where practical and implement refresh-token rotation or short-lived scoped access tokens.
- Scope tokens to the minimum API permissions needed for the requested operation.
- Provide a reliable cross-session revocation mechanism that does not depend on retaining the original device code.
- Delete local credentials securely on logout, revocation, expiry, validation failure, or tenant-context change.
- Never include the token in logs, errors, command histories, telemetry, or user-visible output.
