T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- scripts/post_tweet.py:14
- Finding
- Unvalidated User Identifier Allows Cross-Account Credential Selection and Path Traversal## Vulnerability Details **File Location**: `scripts/get_timeline.py:10-16`, `scripts/get_user_tweets.py:10-16`, `scripts/like_tweet.py:10-16`, `scripts/post_tweet.py:14-21`, `scripts/reply_tweet.py:10-16`, `scripts/retweet.py:10-16`, and `scripts/search_tweets.py:11-17` **Vulnerability Type**: Improper access control and path traversal **Risk Level**: High ### Vulnerable Code The following representative implementation appears in `scripts/post_tweet.py:14-21`: ```python def load_credentials(user_id): """Load Twitter credentials for user""" cred_path = os.path.join(SKILL_DIR, 'credentials', f'{user_id}.json') if not os.path.exists(cred_path): raise Exception(f"No credentials found for user {user_id}. Configure Twitter credentials first.") with open(cred_path, 'r') as f: creds = json.load(f) ``` The same credential-path construction pattern is repeated across all seven scripts: ```python cred_path = os.path.join(SKILL_DIR, 'credentials', f'{user_id}.json') ``` ### Technical Analysis The caller directly controls `user_id`, which is interpolated into a filesystem path without format validation, canonicalization, or a containment check. There is also no authorization check that binds the requested `user_id` to the authenticated caller. This creates two related access-control weaknesses: 1. A caller who knows another user's identifier can select that user's credential file directly. 2. Path components such as `..` can escape the intended `credentials` directory. Because the implementation appends `.json`, the target must be a reachable JSON file with a compatible `twitter` object. The credentials are subsequently used to call X APIs. Although the scripts do not print the credentials directly, an attacker can potentially use another account's credentials indirectly through the supported read and write operations. ### Attack Path 1. The attacker obtains the ability to invok ...[truncated 1513 chars]
- Remediation
- ## Remediation Suggestions 1. Validate `user_id` against a strict allowlist before using it in a path. For example, permit only the exact identifier format required by the application: ```python import re if not re.fullmatch(r'[A-Za-z0-9_-]+', user_id): raise ValueError("Invalid user identifier") ``` 2. Resolve and verify the canonical credential path: ```python credentials_dir = os.path.realpath(os.path.join(SKILL_DIR, "credentials")) cred_path = os.path.realpath( os.path.join(credentials_dir, f"{user_id}.json") ) if os.path.commonpath([credentials_dir, cred_path]) != credentials_dir: raise ValueError("Credential path escapes the credential directory") ``` 3. Do not treat a caller-supplied account identifier as proof of authorization. Obtain the user identity from a trusted authentication context and map it internally to the appropriate credential record. 4. Centralize credential loading in one hardened module rather than duplicating the vulnerable implementation across every script. 5. Use opaque internal credential-record identifiers where practical, and ensure that a caller can access only records explicitly assigned to that caller. 6. Add tests covering absolute paths, `..` traversal, encoded separators, symbolic links, malformed identifiers, and attempts to select another user's credentials. 7. After remediation, review invocation logs for suspicious user identifiers and rotate tokens if cross-account use may already have occurred.
