T09 · Insecure Skill Coding Practices
- Location
scripts/starknet_toolkit.py:220- Finding
Path Traversal, File Overwrite, and Cairo Source Injection in Scaffold Generation
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This Starknet toolkit mostly matches its stated purpose, but its scaffold command can overwrite or create Cairo files in unintended locations from unchecked input.
Review before installing. The read/query features are ordinary public API/RPC use, but run scaffold only in a clean project directory, use simple identifier-like names and symbols, and inspect generated Cairo before compiling or deploying it. The publisher should remove the unused pip dependency and add filename validation, source escaping, and overwrite protection.
scripts/starknet_toolkit.py:220Path Traversal, File Overwrite, and Cairo Source Injection in Scaffold Generation
SKILL.md:32Unnecessary and Unpinned Third-Party Dependency Installation
The module docstring explicitly characterizes the toolkit as 'read-only,' yet the code later opens a file in write mode and saves generated output. This is an active contradiction between stated intent and implemented behavior, not merely omitted detail.
The module docstring describes the skill as a 'read-only Starknet DeFi CLI,' which implies observation, querying, and simulation. However, the documented and implemented 'scaffold' subcommand emits an ERC-20 contract skeleton and writes it to disk, which is code generation rather than read-only DeFi inspection.
Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.
if not token_addr:
print(f"Unknown token {args.token}. Known: {', '.join(MAINNET_TOKENS)}", file=sys.stderr)
sys.exit(1)
selector_balance = "0x2e4263f5f8b3b3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e"
# Real balanceOf selector is 0x2e4263f5f8b3b3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e
# Use the well-known ERC-20 selector for balanceOf
BALANCE_OF_SELECTOR = 0x2e4263f5f8b3b3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e
Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.
if not token_addr:
print(f"Unknown token {args.token}. Known: {', '.join(MAINNET_TOKENS)}", file=sys.stderr)
sys.exit(1)
selector_balance = "0x2e4263f5f8b3b3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e"
# Real balanceOf selector is 0x2e4263f5f8b3b3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e
# Use the well-known ERC-20 selector for balanceOf
BALANCE_OF_SELECTOR = 0x2e4263f5f8b3b3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e
Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.
if not token_addr:
print(f"Unknown token {args.token}. Known: {', '.join(MAINNET_TOKENS)}", file=sys.stderr)
sys.exit(1)
selector_balance = "0x2e4263f5f8b3b3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e"
# Real balanceOf selector is 0x2e4263f5f8b3b3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e
# Use the well-known ERC-20 selector for balanceOf
BALANCE_OF_SELECTOR = 0x2e4263f5f8b3b3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e
Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.
if not token_addr:
print(f"Unknown token {args.token}. Known: {', '.join(MAINNET_TOKENS)}", file=sys.stderr)
sys.exit(1)
selector_balance = "0x2e4263f5f8b3b3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e"
# Real balanceOf selector is 0x2e4263f5f8b3b3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e
# Use the well-known ERC-20 selector for balanceOf
BALANCE_OF_SELECTOR = 0x2e4263f5f8b3b3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e
Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.
if not token_addr:
print(f"Unknown token {args.token}. Known: {', '.join(MAINNET_TOKENS)}", file=sys.stderr)
sys.exit(1)
selector_balance = "0x2e4263f5f8b3b3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e"
# Real balanceOf selector is 0x2e4263f5f8b3b3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e
# Use the well-known ERC-20 selector for balanceOf
BALANCE_OF_SELECTOR = 0x2e4263f5f8b3b3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
def cmd_price(args):
sym = args.symbol.upper()
cg_id = {"STRK": "starknet", "ETH": "ethereum", "USDC": "usd-coin", "USDT": "tether"}.get(sym, sym.lower())
url = f"https://api.coingecko.com/api/v3/simple/price?ids={cg_id}&vs_currencies=usd"
try:
with urllib.request.urlopen(url, timeout=15) as r:
data = json.loads(r.read().decode())
The argparse description presents the tool as a 'Starknet L2 DeFi read/simulate CLI,' but cmd_scaffold creates a new .cairo file on disk. That behavior exceeds a plain read/simulate scope and changes local state.
The scaffold command writes a predictable filename in the current directory without warning, confirmation, or safe-create semantics. In automation or agent contexts, this can overwrite an existing file with the same name and cause loss of local work or unintended artifact creation.
No suspicious patterns detected.