Back to skill

Security audit

Dropbox Integration

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to provide the advertised read-only Dropbox access, but it handles broad Dropbox access tokens in local plaintext files while overstating how safely those secrets are protected.

Review this carefully before installing. Use App Folder access instead of Full Dropbox if possible, keep credentials.json and token.json out of source control and backups, set restrictive file permissions, and revoke the Dropbox app if either file is exposed. Treat the token file like a password because it can preserve Dropbox read access.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (4)

T09 · Insecure Skill Coding Practices

Warning
Location
setup-oauth.js:45
Finding

OAuth Authorization Response Is Not Protected by State Validation

Content
View full analysis
{ const url = new URL(req.url, `http://${req.headers.host}`); if (url.pathname === '/callback') { const code = url.searchParams.get('code'); const error = url.searchParams.get('error'); ``` ```javascript const tokenResponse = await fetch('https://api.dropboxapi.com/oauth2/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: new URLSearchParams({ code, grant_type: 'authorization_code', client_id: app_key, client_secret: app_secret, redirect_uri: REDIRECT_URI, }), }); ``` ### Technical Analysis The authorization request does not contain a cryptographically random OAuth `state` parameter. The callback consequently cannot verify that the received authorization response corresponds to the authorization flow initiated by the local user. The callback accepts any syntactically valid `code` and immediately exchanges it using the configured application credentials. This creates an OAuth authorization-response injection or login-CSRF condition. The project documentation acknowledges that state management would be needed for production, but the setup script itself remains unprotected. PKCE is also absent. Although PKCE does not replace `state` for all CSRF protections, using both controls would provide stronger binding between the auth ...[truncated 1230 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
setup-oauth.js:139
Finding

OAuth Callback Server Is Exposed Beyond the Loopback Interface

Content
View full analysis
{ console.log('🌐 Local server started on http://localhost:3000'); console.log(' Waiting for authorization...\n'); }); ``` ### Technical Analysis The call to `server.listen` specifies a port but no hostname. In Node.js, this normally causes the server to listen on an unspecified address, potentially accepting connections through non-loopback network interfaces. This exceeds the callback service's requirements: the registered redirect URI is `http://localhost:3000/callback`, so only local connections are needed. The log message incorrectly implies that the service is limited to localhost. The exposure is especially significant because the callback has no OAuth `state` validation and terminates the setup process for several attacker-controlled inputs. ### Attack Path 1. The victim runs `setup-oauth.js` on a host reachable from another local or network-adjacent system. 2. The callback service begins listening on port 3000 through available interfaces. 3. An attacker connects to the victim's port 3000. 4. The attacker submits either: - `/callback?error=...` to terminate or disrupt setup; or - `/callback?code=...` to attempt authorization-response injection. 5. The script processes the untrusted callback because it does not restrict the peer to loopback or validate OAuth state. ### Impact Assessment A network-adjacent attacker may disrupt setup, prematurely close the callback server, or combine the exposure with the missing-state vulnerability to replace the intended authorization result. The callback does not provide general code execution or Dropbox write privileges, but the exposed listener unnecessarily increases the reachable attack surface. ]]>
Remediation
View remediation
{ console.log('Local OAuth callback server started on http://127.0.0.1:3000'); }); ``` Additional hardening should include: 1. Add OAuth `state` validation independently of the bind restriction. 2. Handle only one valid callback and reject subsequent requests. 3. Add a short timeout that closes the server automatically. 4. Validate the callback path, HTTP method, and expected query parameters. 5. Return generic error messages rather than reflecting remote error content into HTML. 6. Where IPv6 localhost support is required, configure and validate loopback-only binding deliberately rather than accepting all interfaces. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:87
Finding

Credential Exclusion Claims Do Not Match the Packaged Files

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
package.json:22
Finding

Dependency Installation Is Not Reproducibly Locked

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (55)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill also references accessing account profile data and storing tokens locally in plaintext JSON, while claiming secure storage and advertising capabilities not demonstrated in the provided content. Such inconsistencies can cause users to underestimate privacy exposure and operational risk when granting Dropbox access.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill also references accessing account profile data and storing tokens locally in plaintext JSON, while claiming secure storage and advertising capabilities not demonstrated in the provided content. Such inconsistencies can cause users to underestimate privacy exposure and operational risk when granting Dropbox access.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
88% confidence
Finding

The skill also references accessing account profile data and storing tokens locally in plaintext JSON, while claiming secure storage and advertising capabilities not demonstrated in the provided content. Such inconsistencies can cause users to underestimate privacy exposure and operational risk when granting Dropbox access.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
94% confidence
Finding

The skill instructs users to create a local credentials.json containing the Dropbox app key and app secret. Storing sensitive OAuth client material in plaintext local files is risky because other local users, malware, backups, logs, or accidental commits can expose the secret and enable unauthorized token exchanges.

Content

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

3. Save Credentials

Create credentials.json in the skill directory:

json
{

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

The skill explicitly stores access and refresh tokens in token.json. Refresh tokens are especially sensitive because they enable long-term access renewal; if stolen, an attacker can maintain access to Dropbox contents and metadata without the user's immediate awareness.

Content

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

md
### Authentication Flow

1. **Initial Setup:** User authorizes the app via OAuth 2.0
2. **Token Storage:** Access token + refresh token saved to `token.json`
3. **Auto-Refresh:** Before each API call, checks if token needs refresh
4. **Seamless Access:** Automatically refreshes tokens 5 minutes before expiration

Credential Access

High
Category
Privilege Escalation
Confidence
94% confidence
Finding

The token lifecycle section highlights the presence of long-lived refresh tokens, which materially raises the impact of insecure storage. In a Dropbox integration, theft of such tokens can lead to durable unauthorized access to private files, metadata, and account information despite the read-only scope.

Content

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

md
### Token Lifecycle

- **Access Token:** Short-lived (typically 4 hours)
- **Refresh Token:** Long-lived (doesn't expire unless revoked)
- **Auto-refresh:** Happens transparently in `dropbox-helper.js`
- **Refresh Buffer:** 5 minutes before expiration to prevent edge cases

Credential Access

High
Category
Privilege Escalation
Confidence
91% confidence
Finding

The documented file structure explicitly includes credential-related files, normalizing local secret storage within the skill directory. Even with .gitignore, plaintext secrets remain exposed to local compromise, backup leakage, packaging mistakes, or repository misconfiguration.

Content

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

md
├── search-files.js          # Search files
├── download.js              # Download files
├── test-connection.js       # Test authentication
├── credentials.json.example # Template for credentials
├── .gitignore               # Excludes credentials.json and token.json
└── references/
    └── setup-guide.md       # Detailed setup instructions

Credential Access

High
Category
Privilege Escalation
Confidence
91% confidence
Finding

The documentation states that credentials.json and token.json are excluded by .gitignore, but gitignore is not a security control. Users may assume this makes storage safe, when in reality the files still contain high-value secrets accessible to local processes and prone to accidental exposure through other channels.

Content

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

├── download.js # Download files ├── test-connection.js # Test authentication ├── credentials.json.example # Template for credentials ├── .gitignore # Excludes credentials.json and token.json └── references/ └── setup-guide.md # Detailed setup instructions

text

Credential Access

High
Category
Privilege Escalation
Confidence
93% confidence
Finding

Troubleshooting guidance reinforces the requirement to keep Dropbox app key and secret in credentials.json, which perpetuates insecure secret handling. Because these credentials are directly tied to OAuth operations, disclosure can allow unauthorized app use and facilitate compromise of linked Dropbox access tokens.

Content

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

md
## Troubleshooting

### "credentials.json not found"
Create `credentials.json` with your Dropbox app key and secret (see Quick Start step 3).

### "Token refresh failed"

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

The re-authentication flow implies continued dependence on locally stored client secrets and refresh tokens, increasing the window of exposure for long-lived credentials. In the context of a cloud storage integration, compromise of those materials can provide persistent unauthorized access to sensitive user files and metadata.

Content

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

md
## Troubleshooting

### "credentials.json not found"
Create `credentials.json` with your Dropbox app key and secret (see Quick Start step 3).

### "Token refresh failed"
Your refresh token may have been revoked. Re-run `node setup-oauth.js` to re-authenticate.

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

The skill labels plaintext credentials.json and token.json handling as a security best practice because they are gitignored and have local file permissions. This is misleading and dangerous: it may cause users to overtrust storage that is still vulnerable to local compromise and does not meet the claimed 'secure credential storage' standard.

Content

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

md
## Security Best Practices

1. **Never commit credentials:** `credentials.json` and `token.json` are gitignored
2. **File permissions:** Tokens are saved with mode 0600 (user read/write only)
3. **App-specific tokens:** Each app has its own tokens (easily revokable)
4. **Scope limitation:** Only request permissions you actually need

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 · dropbox-helper.js (reported line 3)May include surrounding context.

js
/**
 * Dropbox Helper with Auto-Refresh
 * Automatically refreshes access tokens when they expire
 */

const { Dropbox } = require('dropbox');

Credential Access

High
Category
Privilege Escalation
Confidence
84% confidence
Finding

The helper reads long-lived OAuth material from local JSON files in the skill directory, including app credentials and tokens. Storing secrets in plaintext files increases the risk of credential disclosure through filesystem access, backups, accidental commits, or other local compromise, which could enable unauthorized Dropbox access.

Content

Scanner excerpt · dropbox-helper.js (reported line 10)May include surrounding context.

js
const fs = require('fs').promises;
const path = require('path');

const CREDENTIALS_PATH = path.join(__dirname, 'credentials.json');
const TOKEN_PATH = path.join(__dirname, 'token.json');

// Buffer time: refresh 5 minutes before actual expiration

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/setup-guide.md (reported line 222)May include surrounding context.

text
✅ Authorization successful!
Your access token has been saved to token.json
You can close this window and return to your terminal.

Credential Access

High
Category
Privilege Escalation
Confidence
82% confidence
Finding

The guide's sample terminal output displays both an access token and refresh token, normalizing the practice of printing secrets to the console. Even though the values are illustrative, documenting this behavior encourages implementations that expose reusable credentials in shell history, logs, screenshots, or shared terminals.

Content

Scanner excerpt · references/setup-guide.md (reported line 234)May include surrounding context.

✅ Success! Token saved to token.json

Token details:

  • Access token: sl.B3g5xyz...
  • Refresh token: abc123xyz...
  • This token will not expire (use refresh token to get new access tokens)
text

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/setup-guide.md (reported line 236)May include surrounding context.

Token details:

  • Access token: sl.B3g5xyz...
  • Refresh token: abc123xyz...
  • This token will not expire (use refresh token to get new access tokens)
text

Your `token.json` file now contains:

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 · dropbox-helper.js (reported line 68)May include surrounding context.

js
/**
 * Dropbox OAuth 2.0 Setup Script
 * 
 * This script helps you get an access token for your Dropbox account.
 * 
 * Usage:
 *   1. Create credentials.json with your app key and secret

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 · dropbox-helper.js (reported line 71)May include surrounding context.

js
/**
 * Dropbox OAuth 2.0 Setup Script
 * 
 * This script helps you get an access token for your Dropbox account.
 * 
 * Usage:
 *   1. Create credentials.json with your app key and secret

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 · setup-oauth.js (reported line 6)May include surrounding context.

js
/**
 * Dropbox OAuth 2.0 Setup Script
 * 
 * This script helps you get an access token for your Dropbox account.
 * 
 * Usage:
 *   1. Create credentials.json with your app key and secret

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 · setup-oauth.js (reported line 111)May include surrounding context.

js
/**
 * Dropbox OAuth 2.0 Setup Script
 * 
 * This script helps you get an access token for your Dropbox account.
 * 
 * Usage:
 *   1. Create credentials.json with your app key and secret

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/setup-guide.md (reported line 136)May include surrounding context.

md
* This script helps you get an access token for your Dropbox account.
 * 
 * Usage:
 *   1. Create credentials.json with your app key and secret
 *   2. Run: node setup-oauth.js
 *   3. Follow the authorization URL in your browser
 *   4. Paste the authorization code when prompted

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/setup-guide.md (reported line 138)May include surrounding context.

md
* This script helps you get an access token for your Dropbox account.
 * 
 * Usage:
 *   1. Create credentials.json with your app key and secret
 *   2. Run: node setup-oauth.js
 *   3. Follow the authorization URL in your browser
 *   4. Paste the authorization code when prompted

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/setup-guide.md (reported line 160)May include surrounding context.

md
* This script helps you get an access token for your Dropbox account.
 * 
 * Usage:
 *   1. Create credentials.json with your app key and secret
 *   2. Run: node setup-oauth.js
 *   3. Follow the authorization URL in your browser
 *   4. Paste the authorization code when prompted

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/setup-guide.md (reported line 163)May include surrounding context.

md
* This script helps you get an access token for your Dropbox account.
 * 
 * Usage:
 *   1. Create credentials.json with your app key and secret
 *   2. Run: node setup-oauth.js
 *   3. Follow the authorization URL in your browser
 *   4. Paste the authorization code when prompted

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/setup-guide.md (reported line 307)May include surrounding context.

md
* This script helps you get an access token for your Dropbox account.
 * 
 * Usage:
 *   1. Create credentials.json with your app key and secret
 *   2. Run: node setup-oauth.js
 *   3. Follow the authorization URL in your browser
 *   4. Paste the authorization code when prompted

Static analysis

Detected: suspicious.exposed_secret_literal, suspicious.potential_exfiltration

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
dropbox-helper.js:49

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
test-connection.js:20

Sensitive-looking file read is paired with a network send.

Warn
Code
suspicious.potential_exfiltration
Location
dropbox-helper.js:31

Sensitive-looking file read is paired with a network send.

Warn
Code
suspicious.potential_exfiltration
Location
test-connection.js:19