T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/cart_link.py:58
- Finding
- Guest cart bearer token exposed through unsafe temporary files and standard output<![CDATA[ ## Vulnerability Details **File Locations**: - `scripts/_auth.py:37-44` - `scripts/_auth.py:105-125` - `scripts/cart_link.py:58-60` - `scripts/cart_link.py:65-97` - `scripts/cart_link.py:204-218` - `scripts/cart_link.py:277` **Vulnerability Type**: Sensitive token exposure through unsafe temporary-file handling and logging **Risk Level**: Medium ### Vulnerable Code Token cache path creation: ```python def _cache_path() -> Path: base = os.environ.get("TARGET_TOKEN_CACHE_DIR") if base: d = Path(base) else: d = Path(tempfile.gettempdir()) / "target-com-shopper" d.mkdir(parents=True, exist_ok=True) return d / "anonymous-token.json" ``` The token is written before restrictive permissions are applied: ```python def get_token(*, force_refresh: bool = False) -> dict[str, Any]: """Return a cached token if still valid, otherwise mint and cache a new one. The cache is a plain JSON file under TARGET_TOKEN_CACHE_DIR (or a temp dir). """ path = _cache_path() if not force_refresh and path.exists(): try: cached = json.loads(path.read_text()) exp = cached.get("_payload", {}).get("exp", 0) if exp - time.time() > EXPIRY_SKEW_S: return cached except (ValueError, KeyError, OSError): pass fresh = mint_token() try: path.write_text(json.dumps(fresh)) # Tighten perms — token grants cart write access. os.chmod(path, 0o600) except OSError: pass return fresh ``` The redirect file is created in a predictable temporary directory without explicit restrictive permissions: ```python def _default_cart_file(cart_id: str | None) -> Path: base = Path(tempfile.gettempdir()) / "target-com-shopper" base.mkdir(parents=True, exist_ok=True) suffix = cart_id or f"unknown-{int(time.time())}" return base / f"cart-{suffix}.html" ``` The redirect file contains the complete bearer URL: ```pyth ...[truncated 5946 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Create a private cache directory** - Create the directory with mode `0700`. - Verify that it is a real directory, is owned by the current user, and is not a symbolic link. - Prefer a per-user runtime directory such as `$XDG_RUNTIME_DIR` when available. 2. **Create sensitive files securely** - Use exclusive creation with `os.open()` flags such as `O_CREAT | O_EXCL | O_WRONLY`. - Set mode `0600` at creation time rather than applying `chmod()` after writing. - Reject symbolic links with platform-appropriate safeguards such as `O_NOFOLLOW`. - Write to a securely created temporary file and use an atomic rename where replacement is required. 3. **Protect redirect files** - Create bearer-token HTML files with mode `0600`. - Avoid predictable fallback names based only on timestamps. - Use cryptographically random filenames. - Delete the redirect file after successful browser handoff or after a short expiration period. 4. **Remove the full token from default output** - Do not include the complete `url` field in normal command output. - Return only `cart_file`, `auto_opened`, `url_preview`, and non-sensitive shopping-list information by default. - If programmatic access to the URL is required, place it behind an explicit opt-in option such as `--include-sensitive-url`. - Clearly mark opt-in output as sensitive and unsuitable for logs or chat transcripts. 5. **Minimize token lifetime and reuse** - Request the shortest token lifetime supported by the upstream service. - Avoid reusing tokens longer than necessary. - Remove expired cache files promptly. 6. **Add security regression tests** - Assert that the cache directory is mode `0700`. - Assert that cache and redirect files are mode `0600`. - Assert that default stdout does not contain `access_token=`. - Test behavior when paths are pre-existing symbolic links or owned by another user. - Test that sensitive temp ...[truncated 69 chars]
