Back to skill

Security audit

Danube

Security checks for vulnerabilities and agentic risk

Overview

Review before installing: the skill explicitly permits unapproved changes to saved service targets and documents scheduled jobs that exceed the connecting key’s restrictions.

Require confirmation and review existing values before saving or replacing defaults. Use a narrowly scoped API key and deliberately select the intended workspace. Keep scheduling disabled unless you accept its documented use of the author’s credentials without key restrictions and understand who can edit scheduled inputs.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:803
Finding

Automatic persistence of service targets bypasses configuration consent

Content
View full analysis

Impact

The additional write can replace existing defaults and make later calls inherit an unapproved team, organization or application target, including overriding organization-provided defaults. Actual downstream execution or data exposure was not demonstrated.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
Findings (40)

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill explicitly directs the agent to persist parameter defaults 'without asking first,' contradicting its universal confirmation requirement for writes. Those defaults affect later executions and saving them replaces existing values, allowing an unapproved convenience action to change future targets or remove configuration.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

Scheduled persistence is disclosed and requires confirmation, so persistence alone is not a vulnerability. However, the documented execution model drops the initiating key's restrictions and permits non-author managers to change inputs used with the author's credentials, creating a potential privilege-escalation or confused-deputy path if the backend behaves as described.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding

Service discovery, policy inspection, and tool management support the declared tool-access purpose. However, the promotion examples issue POST requests that create named tools without requesting confirmation or implementing a confirmation gate. Owner/admin authorization is not equivalent to explicit confirmation. This finding is limited to the supplied chunk; an external confirmation mechanism is not shown.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

The passage describes a genuine authorization weakness if accurate: requested OAuth scopes are discarded, all MCP tools remain callable, and a Personal connection can reach shared organizations. This is not credential theft by the skill, but it makes the recommended OAuth integration broader than users or clients may intend; the warning does not enforce least privilege.

Content

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

md
never *what*. Past consent the string is dropped rather than narrowed: the approval does not
  carry it to the grant, every connection is created with the full default set, and the token
  response echoes that set back however little you asked for. Nothing enforces it downstream
  either — the access token resolves to the connection's hidden key, which is injected as an
  ordinary `danube-api-key` carrying no permissions — so all 33 MCP tools stay callable. Like
  `?tools=` below, read it as a declaration, not a permission boundary: asking for less is not a
  way to narrow a connection. What does narrow one is a key you issue yourself with

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

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

md
Connected apps page only lists and revokes. The way to hand an agent a restricted credential
  is still a pasted API key with `allowed_services` / `allowed_tools` set on it in the
  dashboard, used instead of an OAuth connection.
- **Tokens are short-lived and rotate.** The access token (`dmcp_at_…`) lasts one hour; the
  refresh token (`dmcp_rt_…`) is spent on every use and replaced, with a 90-day idle expiry.
  **Re-presenting a refresh token you have already exchanged revokes the whole connection** —
  the user has to approve the client again. There is a 30-second grace for the genuine race (a

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

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

md
`invalid_grant`, so the error alone will not tell you which one you just caused.
- **Read the `401` before deciding what to do**, because three different things answer `401` and
  only one of them is fixed by refreshing. A `WWW-Authenticate` carrying `error="invalid_token"`
  is the access token expired or revoked — refresh it. Without that marker the message is the
  tell: "API key required…" means no credential reached the server at all, and "Invalid API key"
  means one did and was rejected (a revoked or mistyped key). Neither of those two is a token
  problem, so refreshing or re-running sign-in will not clear them.

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 · SKILL.md (reported line 827)May include surrounding context.

md
single call. (A default declared in the tool's own schema behaves the opposite way — presence
  of the key is all that counts there, so an explicit `null` wins. These are two different
  mechanisms.) To stop a saved one being filled in, either save the set again without that key —
  a save replaces the object, per the bullet above — or `DELETE
  /services/{id}/parameter-defaults`, which removes **the whole row** for that scope, every
  default in it, not the one key (add `?tool_id=…` to target a tool-scoped row instead). Either
  way, read the list of keys that were filled in rather than assuming your empty value survived:

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · references/troubleshooting.md (reported line 41)May include surrounding context.

md
- The agent is running with the `minimal` tool profile, which hides MCP tools.
  Use `coding` or `messaging`, or check `tools.deny` for `bundle-mcp`.
- **An OAuth connection stopped working after it had been working.** Since 2026-10-04 the
  server issues one-hour access tokens (`dmcp_at_…`) and refresh tokens (`dmcp_rt_…`) that are
  spent on every use. Read the `401` before re-running sign-in: a `WWW-Authenticate` carrying
  `error="invalid_token"` means the access token simply expired or was revoked, and a refresh
  fixes it. Without that marker it is not a token problem and refreshing will not help — the

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · references/troubleshooting.md (reported line 43)May include surrounding context.

md
- **An OAuth connection stopped working after it had been working.** Since 2026-10-04 the
  server issues one-hour access tokens (`dmcp_at_…`) and refresh tokens (`dmcp_rt_…`) that are
  spent on every use. Read the `401` before re-running sign-in: a `WWW-Authenticate` carrying
  `error="invalid_token"` means the access token simply expired or was revoked, and a refresh
  fixes it. Without that marker it is not a token problem and refreshing will not help — the
  message says which: "API key required…" (nothing reached the server) or "Invalid API key"
  (a credential arrived and was rejected). If the refresh

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

md
env:
        - DANUBE_API_KEY
      bins:
        - curl
    primaryEnv: DANUBE_API_KEY
    envVars:
      - name: DANUBE_API_KEY

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
## Guardrails (read these first)

- **Read freely, act with consent.** Discovery — listing services, searching tools, reading schemas, checking ratings, balances, or limits — needs no confirmation. Before any action that **writes, sends, posts, deletes, purchases, spends wallet funds, stores a credential, changes spending limits, or creates/updates/deletes a skill or workflow** — and before **any batch execution** — show the user the exact tool and parameters and get an explicit "yes".
- **Honour the confirmation handshake.** If `execute_tool` comes back with `_meta.confirmation_required: true`, that call will not run until someone consents: show the user the tool and the `parameters` from the response, get an explicit yes, then call again with the `confirm_token` (valid 5 minutes). Never call again with the token without asking. **Re-send your own original parameters, not the ones the response displayed** — those are passed through the redactor first, so a credential-shaped value com

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
mits, or creates/updates/deletes a skill or workflow** — and before **any batch execution** — show the user the exact tool and parameters and get an explicit "yes".
- **Honour the confirmation handshake.** If `execute_tool` comes back with `_meta.confirmation_required: true`, that call will not run until someone consents: show the user the tool and the `parameters` from the response, get an explicit yes, then call again with the `confirm_token` (valid 5 minutes). Never call again with the token without asking. **Re-send your own original parameters, not the ones the response displayed** — those are passed through the redactor first, so a credential-shaped value comes back as `[REDACTED:…]`, while the token is signed over what you actually sent; echoing the masked form back invalidates it.
- **Two separate things raise that handshake, and only one of them is a setting on the key.** Either the account's key carries `require_confirmation`, *or* the tool itself demands consent from every c

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · references/troubleshooting.md (reported line 256)May include surrounding context.

md
`reason`, so you cannot tell there. Either way this response is where the token comes from — together with the tool and the parameters, shown through the redactor (a credential-shaped value reads `[REDACTED:…]`) | Not a failure. Show the user that tool and those parameters, get an explicit yes, then call again with the `confirm_token` (valid 5 minutes) and your **original** parameters — the token is signed over what you sent, so replaying a masked display value is rejected. Never reuse a token without asking, and never loop on the 409 |
| A call that writes or sends went through with **no** confirmation prompt, and you want to know whether the platform vetted it | It didn't. The gate reads the publisher's `metadata.destructive` first and takes it as final; only a row without that key falls through to the method test, which counts anything but GET/HEAD/OPTIONS destructive (an HTTP verb or `COMPOSITE`). A tool served by an MCP server carries the method `MCP`, which says nothing about wh

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

Or let the user authorize this agent with the OAuth 2.0 Device Authorization flow (RFC 8628):

bash
curl -s -X POST https://api.danubeai.com/v1/auth/device/code \
  -H "Content-Type: application/json" -d '{"client_name": "OpenClaw"}'
# → {"device_code": "...", "user_code": "XXXX-XXXX", "verification_url": "...", "expires_in": 600,
#    "interval": 5, "org_id": null, "org_name": null}

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

Tell the user to open verification_url in a browser and enter user_code. Then poll:

bash
curl -s -X POST https://api.danubeai.com/v1/auth/device/token \
  -H "Content-Type: application/json" -d '{"device_code": "DEVICE_CODE_FROM_ABOVE"}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

md
### 3b. Or use plain `curl` — no MCP needed

Every capability below is also a REST call against `https://api.danubeai.com/v1` with the header `danube-api-key: $DANUBE_API_KEY`. Copy-paste recipes: `{baseDir}/references/rest-api.md`.

## Working with tools

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/troubleshooting.md (reported line 61)May include surrounding context.

bash
curl -s https://mcp.danubeai.com/health                      # server up? (no auth needed)
curl -s https://api.danubeai.com/health                      # REST backend up? (no auth needed either)
curl -s -o /dev/null -w "%{http_code}\n" "https://api.danubeai.com/v1/tools/search?query=weather" \
  -H "danube-api-key: ${DANUBE_API_KEY}"                      # 200 = key accepted, 401 = rejected

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
above.

The `readOnlyHint: true` direction is the dependable one: the 16 tools carrying it are exactly
the discovery and inspection calls this skill says need no confirmation — `list_services`,
`search_tools`, `get_service_tools`, `describe_tool`, `fetch_result`, `get_context`,
`get_wallet_balance`, `get_spending_limits`, `get_agent_info`, `list_workflows`,
`get_workflow_execution`, `search_skills`, `get_skill`, `get_my_rating`, `get_tool_ratings` and

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

md
may still meet the `422`; there is nothing to report or retry either way, just use `/describe`.

**This file dates a handful of behaviours that way, so here is the one check that tells you which
side of a date you are on — and what it can't tell you.** `GET https://api.danubeai.com/health`
needs no key and reports `started_at`, the boot time of the REST backend process. Since a process
can't be running code that didn't exist when it booted, `uptime_seconds` is a floor on the age of
the code answering you, with no ceiling: a restart reboots the image it already had, so a recent

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

md
summary unless you ask for more (see *A listing is a summary now* below).

**You never have to call either of them to learn how big the catalogue is.** `GET
https://api.danubeai.com/v1/stats/public` needs no key, is rate-limited at 30/minute, and
answers in one cheap call: `{"services": 517, "tools": 12740, "workflows": 0,
"total_executions": 18856}` at 12:16 UTC on 2026-10-23 — the live figure behind the stale count
above. `services` has not moved since 2026-10-10, and in the four days from the previous reading

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/rest-api.md (reported line 8)May include surrounding context.

gates on), or when you want to see raw responses.

bash
BASE="https://api.danubeai.com/v1"
AUTH="danube-api-key: ${DANUBE_API_KEY}"

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/troubleshooting.md (reported line 60)May include surrounding context.

bash
curl -s https://mcp.danubeai.com/health                      # server up? (no auth needed)
curl -s https://api.danubeai.com/health                      # REST backend up? (no auth needed either)
curl -s -o /dev/null -w "%{http_code}\n" "https://api.danubeai.com/v1/tools/search?query=weather" \
  -H "danube-api-key: ${DANUBE_API_KEY}"                      # 200 = key accepted, 401 = rejected

Unbounded Output

Medium
Category
Output Handling
Confidence
60% confidence
Finding

Output size or generation rate is not bounded. Unbounded output enables denial-of-service through resource exhaustion, log flooding, or context-window stuffing.

Content

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

md
- `list_services` is served from a cache refreshed every 60 seconds, so a service connected or published moments ago can be missing from it for up to a minute; `search_tools` and `get_service_tools(service_id)` are not cached. Don't conclude a service doesn't exist from one `list_services` miss; search for one of its tools instead.
- **`get_service_tools` stops at 50 tools over MCP, and nothing in the answer says so.** Its
  `limit` parameter defaults to 50 and the list is simply cut to that length — no total, no
  cursor, no truncation flag — so the rest of a large service's tools are indistinguishable from
  tools it doesn't have. It is not an MCP-server quirk: the cut is unconditional, and the largest
  services in the catalog are `api` ones (Vercel has 407 tools). Live on 2026-10-20: Higgsfield
  carries 105 tool rows, the default call returned 50 and `limit=500` returned all 105 — nothing

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
99% confidence
Finding

This is an explicit instruction to perform an unconfirmed persistent configuration change, not merely a description of platform behavior. The saved identifiers can alter future execution contexts, and replacing existing defaults can affect unrelated later tasks.

Content

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

md
t a real third party. Don't echo them back to the user either; they may belong to a different piece of work. Note also that, unlike `usage`, `examples` has **no time window**: it is the three most recent successes however old, so an entry can predate a change in the tool's schema.
- If a service always needs the same identifier (Vercel `teamId`, a Sentry org slug, a DigitalOcean app id), save it with `set_parameter_defaults(service_id, {"teamId": "…"})` as soon as a call using it has succeeded, without asking first, and tell the user in one line what you saved; they see it on the service's page in the Danube dashboard and can remove it there. Later calls that omit it get it filled in (`_meta.defaults_applied` says which). Don't save one-off values such as a single record id, and never save a key or token this way.
- **A save replaces the stored object for that scope — it does not merge into it.** One row holds
  one `defaults` object per (owner, service, tool-or-all), and a save overwr

The skill instructs the agent to persist parameter defaults without confirmation, despite promising explicit consent before any write.

Medium
Category
Excessive Agency
Confidence
99% confidence
Finding

The instruction to save defaults without asking authorizes a persistent write outside the advertised consent boundary. Since defaults influence subsequent calls and saves overwrite the scope's entire object, this can silently redirect later actions or erase existing defaults.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.