Back to skill

Security audit

freshbooks-mcp

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent FreshBooks shell helper, but it gives broad live accounting write capability and exposes OAuth tokens in ways users should review carefully before installing.

Install only if you intend to let an agent or shell user access FreshBooks with the same authority as the OAuth app. Treat it as write-capable, not read-only: review commands before running POST or PUT examples, avoid using it against production data casually, and do not log or paste the printed OAuth tokens.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (29)

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 10)May include surrounding context.

md
FreshBooks has a real REST API reachable server-side — no browser bridge, no signed-in
tab, no `fpx`. Authentication is **OAuth2 only**: there is no API key and no personal
access token, so a one-time browser authorize flow is unavoidable.

## The two things that break naive clients

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/fb-token.sh (reported line 13)May include surrounding context.

sh
FreshBooks has a real REST API reachable server-side — no browser bridge, no signed-in
tab, no `fpx`. Authentication is **OAuth2 only**: there is no API key and no personal
access token, so a one-time browser authorize flow is unavoidable.

## The two things that break naive clients

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
`references/fb-token.sh`, which persists the rotation before returning, and never point

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
`references/fb-token.sh`, which persists the rotation before returning, and never point

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 109)May include surrounding context.

md
| `invalid_client` on refresh | The refresh grant needs `client_secret` **and** `redirect_uri`, form-encoded — not JSON |
| `invalid_grant` on refresh | The token was already spent. Re-run the bootstrap |
| 404 on a valid-looking record | Wrong identifier for that URL family — run `fb_ids` |
| 401 on every call | Access token stale and refresh failing; check the state file |

See `references/recipes.md` for ready-to-run request bodies and `jq` recipes.

Credential Access

High
Category
Privilege Escalation
Confidence
71% confidence
Finding

The function echoes a valid access token to stdout, which increases the risk of accidental credential disclosure through shell history, command substitution, process tracing, logs, or downstream scripts printing values. In a helper specifically designed for scripting, this context makes exposure more plausible because callers may capture or display the token inadvertently.

Content

Scanner excerpt · references/fb-token.sh (reported line 34)May include surrounding context.

sh
chmod 600 "$FB_STATE"
}

# Echo a valid access token, refreshing (and persisting the rotation) when stale.
fb_access_token() {
  fb_state_init || return 1
  local now exp tok

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill is described as a query tool, but this section documents invoice creation via POST, which can create live financial records. That mismatch increases the chance that a user or downstream agent will invoke destructive or state-changing actions under the false assumption that the skill is read-only.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

These recipes include creating clients, recording payments, accepting estimates, and emailing estimates, all of which modify business state or trigger external actions. In a skill presented as query-oriented, such hidden write capability can lead to unauthorized billing changes, customer communications, or accounting integrity issues.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill clearly enables shell execution and outbound network/API access, but the manifest does not declare any tool scope or permission boundaries. This increases the chance an agent or user invokes it with broader capabilities than expected, including remote writes to FreshBooks, without an explicit trust or consent model.

Content

No source excerpt is available for this finding.

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 73)May include surrounding context.

| jq '.response.result.invoices[] | {id, invoice_number, amount, outstanding, status}'

text

`fb_curl <path> [curl args…]` attaches the bearer token and `Api-Version: alpha`;
everything after the path is passed to `curl`, so writes work too.

## Response envelopes differ per family

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill is described as a query tool, but the documentation states that arbitrary curl arguments are passed through and that writes work too. This is a capability mismatch that can mislead users or agents into invoking a skill believed to be read-only when it can modify external accounting data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill documents a generic API wrapper that forwards curl arguments and supports writes, but it does not prominently warn that using it can modify remote FreshBooks records. Without an explicit warning or confirmation step, users may unintentionally perform destructive or compliance-sensitive actions against live accounting systems.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The later documentation provides explicit POST/write guidance, payload structure, delete semantics, and persistence caveats, confirming the skill is not merely query-focused. In an accounting context, hidden write capability is more dangerous because it can create, alter, or soft-delete financial records while appearing to be a read helper.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest describes a shell skill for querying FreshBooks business data like invoices, clients, payments, and time tracking using curl with a rotating OAuth token. This file instead bootstraps OAuth credentials by generating authorization URLs, exchanging authorization codes, refreshing tokens, and calling the identity endpoint, which is broader than simple data querying and not reflected in the description.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script prints access and refresh tokens in full to stdout, which can expose long-lived credentials to shell history capture, terminal logging, CI logs, process wrappers, or downstream pipes. In a shell-oriented skill, this is especially risky because stdout is commonly redirected or inspected by other tools, turning valid OAuth credentials into easily leaked secrets.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/fb-token.sh (reported line 29)May include surrounding context.

sh
echo "fb: no state at $FB_STATE and FRESHBOOKS_REFRESH_TOKEN unset — run the bootstrap in SKILL.md" >&2
    return 1
  fi
  mkdir -p "$(dirname "$FB_STATE")" && chmod 700 "$(dirname "$FB_STATE")"
  printf '{"refresh_token":"%s","access_token":"","expires_at":0}\n' "$FRESHBOOKS_REFRESH_TOKEN" > "$FB_STATE"
  chmod 600 "$FB_STATE"
}

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/fb-token.sh (reported line 31)May include surrounding context.

sh
fi
  mkdir -p "$(dirname "$FB_STATE")" && chmod 700 "$(dirname "$FB_STATE")"
  printf '{"refresh_token":"%s","access_token":"","expires_at":0}\n' "$FRESHBOOKS_REFRESH_TOKEN" > "$FB_STATE"
  chmod 600 "$FB_STATE"
}

# Echo a valid access token, refreshing (and persisting the rotation) when stale.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/fb-token.sh (reported line 72)May include surrounding context.

sh
fi
  mkdir -p "$(dirname "$FB_STATE")" && chmod 700 "$(dirname "$FB_STATE")"
  printf '{"refresh_token":"%s","access_token":"","expires_at":0}\n' "$FRESHBOOKS_REFRESH_TOKEN" > "$FB_STATE"
  chmod 600 "$FB_STATE"
}

# Echo a valid access token, refreshing (and persisting the rotation) when stale.

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 · references/fb-bootstrap.mjs (reported line 11)May include surrounding context.

js
local rt resp new_rt new_at expires_in created_at
  rt=$(jq -r '.refresh_token' "$FB_STATE")
  resp=$(curl -sS -X POST https://api.freshbooks.com/auth/oauth/token \
    -H 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode "client_id=$FRESHBOOKS_CLIENT_ID" \
    --data-urlencode "client_secret=$FRESHBOOKS_CLIENT_SECRET" \

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 · references/fb-bootstrap.mjs (reported line 12)May include surrounding context.

js
local rt resp new_rt new_at expires_in created_at
  rt=$(jq -r '.refresh_token' "$FB_STATE")
  resp=$(curl -sS -X POST https://api.freshbooks.com/auth/oauth/token \
    -H 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode "client_id=$FRESHBOOKS_CLIENT_ID" \
    --data-urlencode "client_secret=$FRESHBOOKS_CLIENT_SECRET" \

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 · references/fb-token.sh (reported line 50)May include surrounding context.

sh
local rt resp new_rt new_at expires_in created_at
  rt=$(jq -r '.refresh_token' "$FB_STATE")
  resp=$(curl -sS -X POST https://api.freshbooks.com/auth/oauth/token \
    -H 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode "client_id=$FRESHBOOKS_CLIENT_ID" \
    --data-urlencode "client_secret=$FRESHBOOKS_CLIENT_SECRET" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% 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/fb-token.sh (reported line 79)May include surrounding context.

sh
printf '%s' "$new_at"
}

# curl against the FreshBooks API with auth attached. Args after the path are
# passed through to curl, so: fb_curl /path -X POST -d '{...}'
fb_curl() {
  local path="$1"; shift

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The examples instruct users to source ~/.secrets into the shell environment without any guidance on credential hygiene, least privilege, or avoiding accidental exposure through logs, child processes, or shell history. While common in shell workflows, undocumented secret-loading increases the risk of token leakage and unsafe operational practices.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The markdown presents multiple POST and PUT examples that create invoices, clients, payments, time entries, or trigger estimate actions without warning that they mutate live accounting and customer-facing data. This omission makes accidental execution more likely, especially by agents or users assuming examples are safe to run for inspection.

Content

No source excerpt is available for this finding.

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 · references/recipes.md (reported line 47)May include surrounding context.

Create (unverified) — money amounts are strings:

sh
fb_curl "/accounting/account/$ACCT/invoices/invoices" -X POST \
  -H 'Content-Type: application/json' -d '{
  "invoice": {
    "customerid": 123,

Static analysis

No suspicious patterns detected.