T09 · Insecure Skill Coding Practices
- Location
dropbox-sync.py:261- Finding
Deleted Dropbox Documents Remain in Persistent Agent Memory
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill does what it claims, but it handles broad Dropbox content and persistent agent memory with enough scoping and retention problems that users should review it carefully before installing.
Install only if you are comfortable granting read access to the selected Dropbox areas and storing extracted copies in local OpenClaw memory. Prefer the narrowest Dropbox app scope possible, avoid sensitive or shared folders, review the hard-coded folder settings in dropbox-sync.py before manual use, secure ~/.openclaw/.env, and plan how to remove indexed Markdown files if Dropbox content is deleted or should no longer be searchable.
dropbox-sync.py:261Deleted Dropbox Documents Remain in Persistent Agent Memory
dropbox-sync.py:319Untrusted Dropbox Content Is Persisted Directly into Agent Memory
dropbox-sync.py:120Predictable Shared OCR Temporary Paths Allow File Injection and Unsafe Deletion
dropbox-sync.py:17Runtime Ignores Documented Configuration and May Index Unintended Files
setup.sh:44Installer Retrieves and Installs Unpinned Python Dependencies
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
CONFIG_FILE="$SCRIPT_DIR/user-config.json"
OPENCLAW_ENV="$HOME/.openclaw/.env"
echo "╔════════════════════════════════════════════════╗"
echo "║ Dropbox KB Auto - Interactive Setup ║"
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
CONFIG_FILE="$SCRIPT_DIR/user-config.json"
OPENCLAW_ENV="$HOME/.openclaw/.env"
echo "╔════════════════════════════════════════════════╗"
echo "║ Dropbox KB Auto - Interactive Setup ║"
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
echo ""
echo "Next steps:"
echo " 1. Create Dropbox app at https://www.dropbox.com/developers/apps"
echo " 2. Copy credentials to ~/.openclaw/.env (see .env.example)"
echo " 3. Edit config.json to customize folders"
echo " 4. Run: python3 dropbox-sync.py"
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
## Requirements
- OpenClaw installed and running
- Dropbox account with API access ([create app](https://www.dropbox.com/developers/apps))
- Linux or macOS (tested on Ubuntu 24.04, macOS 14+)
## Installation
The skill description explains the technical behavior, but it does not prominently warn users that Dropbox file contents will be ingested into the agent’s knowledge base and then used to answer later prompts. That creates a meaningful privacy and data-governance risk because users may connect sensitive folders without realizing the content becomes searchable by the agent.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
# Debian/Ubuntu
sudo apt-get install -y tesseract-ocr tesseract-ocr-eng poppler-utils
# macOS
brew install tesseract poppler
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
# Debian/Ubuntu
sudo apt-get install -y tesseract-ocr tesseract-ocr-eng poppler-utils
# macOS
brew install tesseract poppler
The skill instructs users to create a Full Dropbox scoped app and store a long-lived refresh token in a local environment file. Persistent credentials tied to broad Dropbox access increase the blast radius if the host, env file, backups, or logs are compromised, enabling ongoing access to potentially all Dropbox content.
### Dropbox App Setup
1. Create app at https://www.dropbox.com/developers/apps
2. Choose **Scoped access** → **Full Dropbox**
3. Enable: `files.metadata.read`, `files.content.read`
4. Generate refresh token via OAuth 2 flow
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
f"&client_secret={env['DROPBOX_FULL_APP_SECRET']}"
).encode()
req = urllib.request.Request(
"https://api.dropboxapi.com/oauth2/token", data=data,
headers={"Content-Type": "application/x-www-form-urlencoded"}
)
return json.loads(urllib.request.urlopen(req).read())["access_token"]
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
f"&client_secret={env['DROPBOX_FULL_APP_SECRET']}"
).encode()
req = urllib.request.Request(
"https://api.dropboxapi.com/oauth2/token", data=data,
headers={"Content-Type": "application/x-www-form-urlencoded"}
)
return json.loads(urllib.request.urlopen(req).read())["access_token"]
This invokes external binaries on untrusted Dropbox-sourced PDF content after first rendering pages to images in a shared /tmp location. While shell injection is not present because arguments are passed as a list, parsing attacker-controlled documents with pdftoppm/tesseract increases exposure to parser bugs, resource exhaustion, and temp-file interference in a multi-user environment.
f.write(data)
tmp = f.name
parts = []
subprocess.run(["pdftoppm", "-r", "150", "-l", "5", tmp, "/tmp/ocr_p"],
capture_output=True, timeout=60)
for img in sorted(Path("/tmp").glob("ocr_p*")):
r = subprocess.run(["tesseract", str(img), "stdout", "-l", "eng+deu"],
This repeatedly executes tesseract over images derived from untrusted PDFs. The risk is not command injection but unsafe processing of attacker-controlled content by external native tools, which can amplify denial-of-service risk across multiple pages/files.
subprocess.run(["pdftoppm", "-r", "150", "-l", "5", tmp, "/tmp/ocr_p"],
capture_output=True, timeout=60)
for img in sorted(Path("/tmp").glob("ocr_p*")):
r = subprocess.run(["tesseract", str(img), "stdout", "-l", "eng+deu"],
capture_output=True, text=True, timeout=30)
parts.append(r.stdout)
img.unlink(missing_ok=True)
This runs tesseract on attacker-controlled image content downloaded from Dropbox. Although it avoids shell injection, it still hands untrusted input to a native parser, which can be abused for denial of service or exploitation of vulnerabilities in the OCR toolchain.
with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as f:
f.write(data)
tmp = f.name
r = subprocess.run(["tesseract", tmp, "stdout", "-l", "eng+deu"],
capture_output=True, text=True, timeout=30)
os.unlink(tmp)
return r.stdout.strip()
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
line = f"[{timestamp}] {msg}\n"
print(msg)
with open(LOG_FILE, "a") as f:
f.write(line)
# ── Main ─────────────────────────────────────────────────────────────────────
The script downloads Dropbox documents and stores extracted contents as local markdown in a knowledge/memory workspace, creating a clear confidentiality risk. In an agent-skill context this is more dangerous because synced private files may become broadly accessible to other tools, prompts, indexes, or users of the local system without explicit consent or scoping.
The installer offers to create a persistent scheduled task that repeatedly runs the indexing script with access to the user's Dropbox-linked environment. Persistence is dangerous because if the indexed script or its dependencies are later modified, the cron job will continue executing them automatically, extending the blast radius and duration of compromise.
# Create cron job
echo "⏰ Automated Sync Schedule"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
read -p "Create cron job for automatic syncing? [Y/n]: " create_cron
if [[ ! "$create_cron" =~ ^[Nn]$ ]]; then
echo " How often should indexing run?"
echo " 1) Every 6 hours (recommended)"
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
# Check if Debian/Ubuntu
if command -v apt-get &> /dev/null; then
echo " Installing system packages via apt..."
sudo apt-get update
sudo apt-get install -y tesseract-ocr tesseract-ocr-eng tesseract-ocr-deu poppler-utils python3-pip
elif command -v yum &> /dev/null; then
echo " Installing system packages via yum..."
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
# Check if Debian/Ubuntu
if command -v apt-get &> /dev/null; then
echo " Installing system packages via apt..."
sudo apt-get update
sudo apt-get install -y tesseract-ocr tesseract-ocr-eng tesseract-ocr-deu poppler-utils python3-pip
elif command -v yum &> /dev/null; then
echo " Installing system packages via yum..."
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
# Check if Debian/Ubuntu
if command -v apt-get &> /dev/null; then
echo " Installing system packages via apt..."
sudo apt-get update
sudo apt-get install -y tesseract-ocr tesseract-ocr-eng tesseract-ocr-deu poppler-utils python3-pip
elif command -v yum &> /dev/null; then
echo " Installing system packages via yum..."
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
echo "🎉 Setup complete!"
echo ""
echo "Next steps:"
echo " 1. Create Dropbox app at https://www.dropbox.com/developers/apps"
echo " 2. Copy credentials to ~/.openclaw/.env (see .env.example)"
echo " 3. Edit config.json to customize folders"
echo " 4. Run: python3 dropbox-sync.py"
The script reads DROPBOX_FULL_REFRESH_TOKEN, DROPBOX_FULL_APP_KEY, and DROPBOX_FULL_APP_SECRET from ~/.openclaw/.env and uses them to obtain an access token. While this is part of authentication, the file lacks any explicit disclosure in code comments or docstrings that it accesses stored credentials, which matches the missing-warning criterion for sensitive environment or credential access.
This shell installer writes a new user-config.json file and later overwrites dropbox-sync.py, which are file-modifying operations. Although the script prints status messages when saving and updating, it does not disclose in advance that it will modify these local files or that rerunning the installer will rewrite existing configuration/script content.
The closing instruction tells the user to ask the agent using the English phrase 'Search my Dropbox for...' and does not indicate that other languages are supported. This can be read as forcing an English-language interaction pattern without explicit user opt-in or justification.