Back to skill

Security audit

Clawfeed

Security checks for vulnerabilities and agentic risk

Overview

ClawFeed appears to be a real news digest app, but it needs Review because some server and test behavior can affect more than a user would reasonably expect.

Review before installing or deploying. Run it only in a controlled local or protected environment, set strong API/session/OAuth secrets, do not expose it publicly without fixing the source-resolver SSRF controls, and do not run npm test unless AI_DIGEST_API and AI_DIGEST_FEED point to an isolated local test server. Use HTTPS-only feedback webhooks and avoid putting API keys in URLs.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (6)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
src/server.mjs:131
Finding

Source resolution permits SSRF through incomplete IP validation and DNS rebinding

Content
View full analysis
Number.isNaN(x) || x < 0 || x > 255)) return true; const [a, b] = p; return ( a === 0 || a === 10 || a === 127 || (a === 169 && b === 254) || (a === 172 && b >= 16 && b <= 31) || (a === 192 && b === 168) || a >= 224 ); } async function assertSafeFetchUrl(rawUrl) { const u = new URL(rawUrl); if (!['http:', 'https:'].includes(u.protocol)) throw new Error('invalid url scheme'); const host = u.hostname; if (host === 'localhost' || host.endsWith('.localhost')) throw new Error('blocked host'); if (isIP(host) && isPrivateOrSpecialIp(host)) throw new Error('blocked host'); const resolved = await lookup(host, { all: true }); if (!resolved.length || resolved.some((r) => isPrivateOrSpecialIp(r.address))) { throw new Error('blocked host'); } } async function httpFetch(url, timeout = 5000, redirectsLeft = 3) { await assertSafeFetchUrl(url); return new Promise((resolve, reject) => { const mod = url.startsWith('https') ? https : http; const r = mod.get(url, { headers: { 'User-Agent': 'AI-Digest/1.0', 'Accept': 'text/html,application/xhtml+xml,application/xml,application/json,*/*' } }, async (resp) => { try { if (resp.statusCode >= 300 && resp.statusCode < 400 && resp.headers.location) { clearTimeout(timer); if (redirectsLeft <= 0) return reject(new Error('too many redirects')); const nextUrl = ...[truncated 3562 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
test/e2e.sh:10
Finding

E2E tests perform destructive authenticated operations against a remote service by default

Content
View full analysis
/dev/null SD_SRC=$(curl -s -X POST "$API/sources" -H "$ALICE" \ -H "Content-Type: application/json" \ -d '{"name":"SoftDel Test","type":"rss","config":"{\"url\":\"https://softdel.test/rss\"}","isPublic":true}' | jq_val "d['id']") curl -s -X DELETE "$API/sources/$SD_SRC" -H "$ALICE" > /dev/null ``` The package entry point invokes this script directly: ```json { "scripts": { "test": "bash test/e2e.sh" } } ``` ### Technical Analysis Running `npm ...[truncated 1655 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/server.mjs:33
Finding

OAuth state protection can fall back to a public constant and is not bound to the initiating browser

Content
View full analysis
10 * 60 * 1000) { return json(res, { error: 'expired oauth state' }, 400); } if (!isAllowedOrigin(st.origin)) { return json(res, { error: 'origin not allowed' }, 400); } origin = st.origin; redirectUri = st.redirectUri || redirectUri; ``` ### Technical Analysis If OAuth client credentials are configured while `OAUTH_STATE_SECRET`, `SESSION_SECRET`, and `API_KEY` are absent, state signatures use the known literal `dev-state-secret`. An attacker can therefore construct arbitrary state values for allowed origins. In addition, the generated nonce is only embedded inside the signed sta ...[truncated 1692 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/server.mjs:790
Finding

Administrative API key is accepted through URL query parameters

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/server.mjs:755
Finding

Feedback identity and message content can be forwarded over plaintext HTTP

Content
View full analysis
{}); r.end(notifBody); } catch {} } return json(res, { ok: true, id }); } ``` ### Technical Analysis When `FEEDBACK_LARK_WEBHOOK` is configured, the server forwards the submitter's name, email address, and up to 200 characters of feedback content to an external endpoint. The implementation explicitly supports both HTTPS and plaintext HTTP. An HTTP webhook allows network observers, compromised routers, transparent proxies, and ...[truncated 1237 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
src/server.mjs:480
Finding

Google OAuth access token is transmitted in the request URL

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (90)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 85)May include surrounding context.

bash
# 1. Copy and edit environment config
cp .env.example .env
# Edit .env with your settings

# 2. Start the API server

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The documentation explicitly claims the tool runs in read-only mode, but later describes unauthenticated write-capable endpoints such as POST /api/digests and PUT /api/config. This contradiction can mislead operators into deploying the service with weaker controls, increasing the chance of unauthorized data modification or configuration tampering.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The credential table says an API_KEY is used to protect digest creation, but the endpoint table marks the write operation as unauthenticated. This inconsistency suggests either missing access control or dangerously misleading documentation, either of which can result in exposed write functionality.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 69)May include surrounding context.

md
Serve `web/index.html` via your reverse proxy or any static file server.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · docs/TESTING.md (reported line 164)May include surrounding context.

md
| 13.1 | POST /digests 无 API key | 401 |
| 13.2 | POST /sources 未登录 | 401 |
| 13.3 | POST /packs/install 未登录 | 401 |
| 13.4 | DELETE /sources 未登录 | 401 |
| 13.5 | GET /marks 未登录 | 401 |

### 14. 边界情况 (2+ cases)

Known Vulnerable Dependency: brace-expansion==1.1.12 — 4 advisory(ies): CVE-2026-13149 (brace-expansion: DoS via exponential-time expansion of consecutive non-expanding); CVE-2026-33750 (brace-expansion: Zero-step sequence causes process hang and memory exhaustion); CVE-2026-14257 (brace-expansion: DoS via unbounded expansion length causing an out-of-memory pro) +1 more

High
Category
Supply Chain
Confidence
95% confidence
Finding

brace-expansion 1.1.12 has multiple reported denial-of-service issues involving pathological brace patterns that can trigger excessive CPU or memory consumption. Even though this instance is a transitive devDependency via minimatch/eslint tooling, it is still a genuine vulnerable package version and could be abused if attacker-controlled glob patterns reach tooling or automation.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: flatted==3.3.3 — 2 advisory(ies): CVE-2026-32141 (flatted vulnerable to unbounded recursion DoS in parse() revive phase); CVE-2026-33228 (Prototype Pollution via parse() in NodeJS flatted)

High
Category
Supply Chain
Confidence
86% confidence
Finding

flatted 3.3.3 is reported vulnerable to unbounded recursion DoS and possible prototype pollution during parse(). In this file it is only brought in through flat-cache used by eslint as a devDependency, so exploitation depends on parsing attacker-controlled serialized cache content, which reduces exposure but does not make the vulnerable version a false positive.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: js-yaml==4.1.1 — 4 advisory(ies): CVE-2026-84375 (js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources); CVE-2026-59869 (js-yaml: YAML merge-key chains can force quadratic CPU consumption); GHSA-5p4m-2wfm-xmqj (JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and 4.x) — CVE-2026) +1 more

High
Category
Supply Chain
Confidence
93% confidence
Finding

js-yaml 4.1.1 has advisories for CPU exhaustion from crafted YAML structures such as merge-key chains and omap processing. Here it is a transitive devDependency of eslint configuration parsing, so the risk is mostly during development/CI when processing untrusted YAML or repository content, but the vulnerable version is still genuine.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: minimatch==3.1.3 — 1 advisory(ies): CVE-2026-27904 (minimatch ReDoS: nested *() extglobs generate catastrophically backtracking regu)

High
Category
Supply Chain
Confidence
94% confidence
Finding

minimatch 3.1.3 is flagged for ReDoS via crafted nested extglob patterns causing catastrophic backtracking. In this lockfile it is used transitively by eslint-related dev tooling, so exploitation is most plausible where attacker-supplied patterns are evaluated in development or CI; the package version remains vulnerable even if runtime exposure is limited.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · CONTRIBUTING.md (reported line 9)May include surrounding context.

md
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = join(__dirname, '..');

// Load .env
const envPath = join(ROOT, '.env');
const env = {};
if (existsSync(envPath)) {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 86)May include surrounding context.

md
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = join(__dirname, '..');

// Load .env
const envPath = join(ROOT, '.env');
const env = {};
if (existsSync(envPath)) {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 25)May include surrounding context.

md
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = join(__dirname, '..');

// Load .env
const envPath = join(ROOT, '.env');
const env = {};
if (existsSync(envPath)) {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 26)May include surrounding context.

md
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = join(__dirname, '..');

// Load .env
const envPath = join(ROOT, '.env');
const env = {};
if (existsSync(envPath)) {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · src/db.mjs (reported line 9)May include surrounding context.

js
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = join(__dirname, '..');

// Load .env
const envPath = join(ROOT, '.env');
const env = {};
if (existsSync(envPath)) {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · src/server.mjs (reported line 15)May include surrounding context.

js
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = join(__dirname, '..');

// Load .env
const envPath = join(ROOT, '.env');
const env = {};
if (existsSync(envPath)) {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · src/db.mjs (reported line 10)May include surrounding context.

js
const ROOT = join(__dirname, '..');

// Load .env
const envPath = join(ROOT, '.env');
const env = {};
if (existsSync(envPath)) {
  for (const line of readFileSync(envPath, 'utf8').split('\n')) {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · src/server.mjs (reported line 16)May include surrounding context.

js
const ROOT = join(__dirname, '..');

// Load .env
const envPath = join(ROOT, '.env');
const env = {};
if (existsSync(envPath)) {
  for (const line of readFileSync(envPath, 'utf8').split('\n')) {

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · test/README.md (reported line 106)May include surrounding context.

md
### 4. Source Ownership (3 tests)
| # | Case | Method |
|---|------|--------|
| 4.1 | Bob cannot delete Alice's source → 403 | `DELETE /sources/:id` |
| 4.2 | Alice deletes her private source | `DELETE /sources/:id` |
| 4.3 | Alice's subscription count decreases | `GET /subscriptions` |

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · test/README.md (reported line 107)May include surrounding context.

md
### 4. Source Ownership (3 tests)
| # | Case | Method |
|---|------|--------|
| 4.1 | Bob cannot delete Alice's source → 403 | `DELETE /sources/:id` |
| 4.2 | Alice deletes her private source | `DELETE /sources/:id` |
| 4.3 | Alice's subscription count decreases | `GET /subscriptions` |

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · test/README.md (reported line 174)May include surrounding context.

md
### 4. Source Ownership (3 tests)
| # | Case | Method |
|---|------|--------|
| 4.1 | Bob cannot delete Alice's source → 403 | `DELETE /sources/:id` |
| 4.2 | Alice deletes her private source | `DELETE /sources/:id` |
| 4.3 | Alice's subscription count decreases | `GET /subscriptions` |

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · test/README.md (reported line 188)May include surrounding context.

md
### 4. Source Ownership (3 tests)
| # | Case | Method |
|---|------|--------|
| 4.1 | Bob cannot delete Alice's source → 403 | `DELETE /sources/:id` |
| 4.2 | Alice deletes her private source | `DELETE /sources/:id` |
| 4.3 | Alice's subscription count decreases | `GET /subscriptions` |

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · test/README.md (reported line 198)May include surrounding context.

md
### 4. Source Ownership (3 tests)
| # | Case | Method |
|---|------|--------|
| 4.1 | Bob cannot delete Alice's source → 403 | `DELETE /sources/:id` |
| 4.2 | Alice deletes her private source | `DELETE /sources/:id` |
| 4.3 | Alice's subscription count decreases | `GET /subscriptions` |

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · test/README.md (reported line 220)May include surrounding context.

md
### 4. Source Ownership (3 tests)
| # | Case | Method |
|---|------|--------|
| 4.1 | Bob cannot delete Alice's source → 403 | `DELETE /sources/:id` |
| 4.2 | Alice deletes her private source | `DELETE /sources/:id` |
| 4.3 | Alice's subscription count decreases | `GET /subscriptions` |

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · test/README.md (reported line 140)May include surrounding context.

md
### 9. Subscription Management (2 tests)
| # | Case | Method |
|---|------|--------|
| 9.1 | Carol unsubscribes → count decreases | `DELETE /subscriptions/:sourceId` |
| 9.2 | Carol re-subscribes → count restores | `POST /subscriptions` |

### 10. Marks — CRUD + Isolation (7 tests)

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · test/e2e.sh (reported line 274)May include surrounding context.

sh
# Visitor blocked
  check_code "Visitor cannot access marks → 401" "401" \
    "$(curl -s -o /dev/null -w '%{http_code}' "$API/marks")"

  # Alice deletes her mark
  if [ -n "$A_MARK" ] && [ "$A_MARK" != "None" ]; then