Suspicious — Risk Score 40/100
Last scan:1 day ago Rescan
40 /100
openclaw-usage-manager
Real-time usage dashboard and auto-switcher for dual Claude Max accounts
This is a legitimate dual-account Claude Max usage manager, but it stores API tokens unencrypted in plaintext files and modifies OpenClaw auth profiles with no declared credentials handling in SKILL.md — a significant doc-to-code mismatch for a credential-accessing tool.
Skill Nameopenclaw-usage-manager
Duration61.1s
Enginepi
Use with caution
SKILL.md must declare filesystem:WRITE for token/auth storage, document the plaintext token persistence model, and explain why unencrypted credentials on disk are acceptable. Consider encrypting tokens.json or referencing a secret manager instead of storing raw Bearer tokens.

Findings 5 items

Severity Finding Location
High
API tokens stored in plaintext on disk Credential Theft
Both setup scripts write raw Bearer tokens (sk-ant-...) to ~/.openclaw/workspace/tools/usage-switch/tokens.json as unencrypted JSON. Even with chmod 600, the tokens are recoverable by any process running as the user. SKILL.md does not document this token storage model.
data = {'c1': os.environ['C1_TOKEN'], 'c2': os.environ['C2_TOKEN']}
with open(path, 'w') as f:
    json.dump(data, f, indent=2)
→ Document the token persistence model in SKILL.md. Consider encrypting tokens.json at rest using a tool like gpg or keychain-access, or rely solely on 1Password CLI retrieval at runtime (do not write tokens to disk).
usage-switch/setup-tokens.sh:17
High
Undeclared modification of OpenClaw agent auth profiles Credential Theft
check.mjs reads and rewrites ~/.openclaw/agents/main/agent/auth-profiles.json at runtime to perform account switching. This modifies the agent's active authentication configuration — a sensitive operation — with no declaration in SKILL.md.
auth.profiles['anthropic:default'].token = altToken
writeFileSync(tmpFile, JSON.stringify(auth, null, 2))
renameSync(tmpFile, AUTH_FILE)
→ Declare in SKILL.md that this skill reads and modifies OpenClaw agent auth profiles. This is critical information for users who rely on OpenClaw's own auth security model.
usage-switch/check.mjs:61
Medium
SKILL.md does not declare any credential handling, token storage, or auth profile access Doc Mismatch
SKILL.md describes a dashboard and auto-switcher but omits all credential operations: reading tokens from 1Password, storing them in tokens.json, and modifying auth-profiles.json. This doc-to-code mismatch is the highest-value security signal in this analysis.
SKILL.md: 'Security-audited: Reviewed by Claude Code + Codex before release' — yet credential access is completely undeclared
→ Add a 'Credential Handling' section to SKILL.md explaining: (1) tokens are read from 1Password or stdin, (2) stored unencrypted in tokens.json with chmod 600, (3) used to read/write auth-profiles.json for account switching.
SKILL.md:1
Medium
Undeclared filesystem WRITE to OpenClaw agent directory Priv Escalation
check.mjs writes to ~/.openclaw/agents/main/agent/auth-profiles.json — a path inside OpenClaw's own agent infrastructure. SKILL.md declares no filesystem access beyond 'browser dashboard'.
const AUTH_FILE = `${process.env.HOME}/.openclaw/agents/main/agent/auth-profiles.json`;
→ Declare filesystem:WRITE for OpenClaw agent config paths in SKILL.md's capability requirements section.
usage-switch/check.mjs:8
Low
Hardcoded placeholder 1Password item IDs in server.mjs Obfuscation
The dashboard server has hardcoded 'your-c1-item-id' and 'your-c2-item-id' placeholders in ACCOUNTS config. While these are clearly documented as placeholders, leaving them in production code with no validation could cause confusing errors.
c1: { label: 'C1', opItemId: 'your-c1-item-id' }
→ Validate that opItemId values are not placeholder strings before invoking op CLI. This is low risk but improves operational robustness.
usage-dashboard/server.mjs:19
ResourceDeclaredInferredStatusEvidence
Filesystem NONE WRITE ✗ Violation setup-tokens.sh:17 writes to ~/.openclaw/workspace/tools/usage-switch/tokens.jso…
Network NONE READ ✗ Violation server.mjs:58, check.mjs:28 POST to https://api.anthropic.com/v1/messages using …
Shell NONE WRITE ✗ Violation setup-tokens.sh:1, setup-tokens-simple.sh:1 are shell scripts; server.mjs:148 us…
Browser NONE READ ✓ Aligned SKILL.md describes a 'browser dashboard' but browser:READ is not in the declared…
credential NONE WRITE ✗ Violation setup-tokens.sh reads from 1Password CLI (op item get --reveal); check.mjs:65 wr…
Environment NONE READ ✓ Aligned setup-tokens.sh:17, setup-tokens-simple.sh:18 pass C1_TOKEN/C2_TOKEN via os.envi…
5 findings
🔗
Medium External URL 外部 URL
https://x.com/5dmgmt/status/2032770037728113118
README.md:18
🔗
Medium External URL 外部 URL
https://openclaw.ai
README.md:92
🔗
Medium External URL 外部 URL
https://developer.1password.com/docs/cli/
README.md:95
🔗
Medium External URL 外部 URL
https://x.com/5dmgmt
README.md:653
🔗
Medium External URL 外部 URL
https://5dmgmt.com
README.md:655

File Tree

7 files · 49.7 KB · 1333 lines
Markdown 2f · 738L JavaScript 2f · 293L HTML 1f · 248L Shell 2f · 54L
├─ 📁 usage-dashboard
│ ├─ 📄 index.html HTML 248L · 8.7 KB
│ └─ 📜 server.mjs JavaScript 210L · 5.8 KB
├─ 📁 usage-switch
│ ├─ 📜 check.mjs JavaScript 83L · 3.1 KB
│ ├─ 🔑 setup-tokens-simple.sh Shell 31L · 1.0 KB
│ └─ 🔑 setup-tokens.sh Shell 23L · 1.3 KB
├─ 📝 README.md Markdown 655L · 27.0 KB
└─ 📝 SKILL.md Markdown 83L · 2.8 KB

Dependencies 2 items

PackageVersionSourceKnown VulnsNotes
Node.js >= 18 unspecified runtime version runtime No No package.json / package-lock.json found — no npm dependencies. Uses only built-in Node.js modules (http, crypto, child_process, fs, url, path)
1Password CLI (op) latest system binary No External system binary invoked via execSync. SKILL.md declares '1Password CLI recommended' but does not verify installation. Failure is handled gracefully (returns null token)

Security Positives

✓ All network requests target the legitimate Anthropic API endpoint (api.anthropic.com) — no C2 or exfiltration channels detected
✓ Dashboard server binds to 127.0.0.1 only and implements CSRF token validation — good localhost-only design
✓ Atomic file writes using tmp + renameSync pattern for auth-profiles.json — prevents corruption
✓ tokens.json has chmod 600 applied — mitigates other-user file read risk
✓ External URLs point to a named GitHub repo with a real company (5dmgmt.com) — consistent with a legitimate open-source tool, not typosquatting
✓ setup-tokens.sh passes credentials via environment variables to Python rather than string interpolation — mitigates shell injection
✓ server.mjs uses import.meta.url and path-safe file serving — no path traversal vectors
✓ HTML dashboard uses DOM API (createElement) instead of innerHTML — mitigates XSS
✓ AJAX calls to /api/usage require both CSRF token and localhost origin verification — defense in depth