T09 · Insecure Skill Coding Practices
- Location
SKILL.md:5- Finding
Hard-Coded Tavily API Credential Exposed in Skill Documentation and Metadata
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md:5,SKILL.md:17,SKILL.md:24, andSKILL.md:29
Vulnerability Type: Hard-coded API credential and incorrect secret configuration
Risk Level: HighVulnerable Code Snippets
SKILL.md:5yaml metadata: {"openclaw":{"emoji":"🔍","requires":{"bins":["node"],"env":["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"]},"primaryEnv":"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"}}SKILL.md:17json "apiKey": "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"SKILL.md:24bash export TAVILY_API_KEY="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"SKILL.md:29bash node {baseDir}/scripts/search.mjs "query"The credential itself is exposed on lines 5, 17, and 24. Line 29 begins the documented execution flow that causes the configured credential to be consumed by the search script.
Technical Analysis
A Tavily development API credential is embedded directly in the distributed
SKILL.mdfile. Anyone with access to the Skill package can extract and use this credential independently of the Skill.The metadata on line 5 also uses the credential value itself as both an environment-variable requirement and the
primaryEnvidentifier. These fields should contain the variable nameTAVILY_API_KEY, not its secret value. This configuration error can interfere with normal secret injection while simultaneously publishing the credential.When the script runs,
scripts/search.mjs:78readsTAVILY_API_KEY, andscripts/search.mjs:94-102transmits it to the declared Tavily HTTPS API as a bearer token:javascript const apiKey = (process.env.TAVILY_API_KEY ?? "").trim(); const resp = await fetch("https://api.tavily.com/search", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` ...[truncated 1664 chars]- Remediation
View remediation
Remediation Suggestions
- Revoke the exposed credential immediately. Treat it as compromised even if unauthorized use has not yet been detected.
- Generate a replacement key through Tavily and store it only in an approved secret manager or protected runtime configuration.
- Correct the Skill metadata so that it refers to the environment-variable name rather than a credential:
yaml metadata: {"openclaw":{"emoji":"🔍","requires":{"bins":["node"],"env":["TAVILY_API_KEY"]},"primaryEnv":"TAVILY_API_KEY"}} - Replace documentation secrets with placeholders, for example:
json { "skills": { "entries": { "tavily-search": { "enabled": true, "apiKey": "YOUR_TAVILY_API_KEY" } } } }bash export TAVILY_API_KEY="YOUR_TAVILY_API_KEY" - Inspect repository and package history. Removing the key from the current file does not remove it from prior commits, release archives, caches, or mirrors.
- Review provider logs and billing records for requests made using the exposed key, including unusual volume, source addresses, or query patterns.
- Add automated secret scanning to pre-commit hooks and CI pipelines to reject credential patterns before publication.
- Apply least privilege and usage controls to the replacement key, including quota limits, alerts, rotation schedules, and provider-supported restrictions.
