T09 · Insecure Skill Coding Practices
- Location
ingest.sh:42- Finding
Python Code Injection Through Unescaped Ingestion Parameters and Document Data
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is a Qdrant/OpenAI toolkit, but its scripts are unsafe enough that crafted inputs or database records could run local code and sensitive text can leave the machine.
Install only after review and preferably after patching. Avoid sensitive documents, queries, or production Qdrant data until the Python interpolation bugs are fixed, OpenAI data transmission is explicitly approved, and Qdrant access supports HTTPS and authentication. Treat delete, restore, and migration commands as high-impact operations and verify backups before use.
ingest.sh:42Python Code Injection Through Unescaped Ingestion Parameters and Document Data
search.sh:101Python Code Injection Through Search Query and Collection Arguments
migrate.sh:143Python Code Injection During Collection Migration
manage.sh:6Qdrant Credentials Are Ignored and Database Traffic Uses Plain HTTP
The skill claims a broad production-ready feature set, but the documented behavior appears to overstate what is actually implemented. This mismatch can cause operators or agents to rely on nonexistent safeguards, backup flows, migration controls, or ingestion semantics, leading to unsafe operational decisions and misuse of the scripts.
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).
GET /collections # List collections
PUT /collections/{name} # Create collection
DELETE /collections/{name} # Delete collection
GET /collections/{name} # Collection info
POST /collections/{name}/points/search # Search
PUT /collections/{name}/points # Upsert points
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.
echo ""
echo "Collection details:"
for name in $(echo "$BODY" | python3 -c "import json,sys; [print(c['name']) for c in json.load(sys.stdin)['result']['collections']]"); do
INFO=$(curl -s "${QDRANT_URL}/collections/${name}")
POINTS=$(echo "$INFO" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('result', {}).get('points_count', 0))")
VECTORS=$(echo "$INFO" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('result', {}).get('config', {}).get('params', {}).get('vectors', {}).get('size', 'N/A'))")
DISTANCE=$(echo "$INFO" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('result', {}).get('config', {}).get('params', {}).get('vectors', {}).get('distance', 'N/A'))")
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.
")
fi
local scroll_resp=$(curl -s -X POST \
-H "Content-Type: application/json" \
"${QDRANT_URL}/collections/${SOURCE}/points/scroll" \
-d "$scroll_payload")
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.
# Extract texts and re-embed
local texts=$(echo "$points" | python3 -c "import json,sys; pts=json.load(sys.stdin); print(json.dumps([p.get('payload', {}).get('text', '') for p in pts]))")
local emb_resp=$(curl -s -X POST \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
https://api.openai.com/v1/embeddings \
The README describes ingestion, search, and model-upgrade workflows using OpenAI embeddings but does not warn that document contents and queries may be sent to an external API provider. In an AI-agent skill context, users may process sensitive files under the assumption operations are local, creating a meaningful confidentiality and compliance risk.
The README documents destructive operations such as collection deletion and snapshot deletion/restore without any warning, confirmation guidance, or emphasis on irreversibility. In an agent-oriented skill, these examples can be invoked programmatically or copied directly, increasing the chance of accidental data loss in production Qdrant environments.
The skill documents shell execution and file access behavior but does not declare any explicit tool scope such as permissions or allowed-tools. That increases the chance an agent can invoke broader shell or file capabilities than a reviewer or runtime policy expects, weakening least-privilege controls.
The ingestion workflow requires an OpenAI API key for embeddings, which implies document contents may be transmitted to an external service, but the documentation omits any privacy or data handling warning. This can lead to unintentional exfiltration of sensitive documents, credentials, or regulated data during ingestion.
The documentation presents collection deletion as a normal command without any warning, confirmation step, or recovery guidance. In an agent-driven environment, this makes accidental or prompt-induced destructive actions more likely, causing irreversible data loss or service disruption.
Restore is documented without warning that it may overwrite, replace, or otherwise alter an existing collection state. Users or agents may invoke it assuming it is non-destructive, leading to corruption, rollback, or loss of current production data.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
echo "Creating snapshot '$SNAPSHOT_NAME' for collection '$COLLECTION'..."
RESPONSE=$(curl -s -w "\n%{http_code}" \
-X POST \
-H "Content-Type: application/json" \
"${QDRANT_URL}/collections/${COLLECTION}/snapshots" \
This curl call transmits chunked document content to an external service for embedding generation. Although this is aligned with the skill's stated purpose, it creates a genuine confidentiality risk if secrets, regulated data, or proprietary content are ingested without clear disclosure or controls.
local batch_num="$2"
# Generate embeddings for batch
local embedding_response=$(curl -s -w "\n%{http_code}" \
-X POST \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
The script sends raw document chunks to OpenAI's embeddings API, which means file contents leave the local environment and are disclosed to a third party. In a document-ingestion skill, this is expected functionality, but it is still a real privacy and data-handling risk because users may unknowingly process sensitive documents without an explicit warning, consent gate, or data-classification check.
The hardcoded OpenAI API endpoint confirms that document data is sent to an external third-party service. In context this is not malicious, but it increases risk because the destination is outside the user's infrastructure and there is no in-script warning, consent mechanism, or data sensitivity guardrail.
-X POST \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
https://api.openai.com/v1/embeddings \
-d "{
\"input\": $batch_data,
\"model\": \"text-embedding-3-small\"
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
)
# Upload to Qdrant
local upload_response=$(curl -s -w "\n%{http_code}" \
-X PUT \
-H "Content-Type: application/json" \
"${QDRANT_URL}/collections/${COLLECTION}/points" \
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
echo "Creating collection '$COLLECTION_NAME' (${DIMENSION}d, $DISTANCE)..."
RESPONSE=$(curl -s -w "\n%{http_code}" \
-X PUT \
-H "Content-Type: application/json" \
"${QDRANT_URL}/collections/${COLLECTION_NAME}" \
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
fi
else
echo " Creating target collection (${TARGET_DIM}d, $TARGET_DIST)..."
CREATE_RESP=$(curl -s -w "\n%{http_code}" \
-X PUT \
-H "Content-Type: application/json" \
"${QDRANT_URL}/collections/${TARGET}" \
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
")
fi
local scroll_resp=$(curl -s -X POST \
-H "Content-Type: application/json" \
"${QDRANT_URL}/collections/${SOURCE}/points/scroll" \
-d "$scroll_payload")
When --upgrade-model is enabled, the script extracts payload text from Qdrant points and sends it to the OpenAI embeddings API. This creates a real data disclosure risk because collection contents may include sensitive or proprietary text, and the script does not provide an explicit warning, consent gate, or redaction step before transmission.
This call sends extracted collection text to an external third-party API for re-embedding. In the context of a vector database migration skill, that is more dangerous because users may run it on production collections containing confidential data, yet the script has no explicit disclosure prompt, sanitization, or policy control.
# Extract texts and re-embed
local texts=$(echo "$points" | python3 -c "import json,sys; pts=json.load(sys.stdin); print(json.dumps([p.get('payload', {}).get('text', '') for p in pts]))")
local emb_resp=$(curl -s -X POST \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
https://api.openai.com/v1/embeddings \
The hardcoded OpenAI API endpoint confirms that model-upgrade mode transmits data outside the local Qdrant environment to a third-party service. Because the transmitted content is derived from payload text, this creates a genuine confidentiality and compliance risk if sensitive records are migrated.
local emb_resp=$(curl -s -X POST \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
https://api.openai.com/v1/embeddings \
-d "{\"input\": $texts, \"model\": \"text-embedding-3-small\"}")
local embeddings=$(echo "$emb_resp" | python3 -c "import json,sys; d=json.load(sys.stdin); print(json.dumps([e['embedding'] for e in d.get('data', [])]))")
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
")
# Upload to target
local upload_resp=$(curl -s -w "\n%{http_code}" \
-X PUT \
-H "Content-Type: application/json" \
"${QDRANT_URL}/collections/${TARGET}/points" \
The script sends user-supplied query text to OpenAI to generate embeddings and requires an external API key from the environment, creating a data-flow dependency outside the local Qdrant system. This is dangerous when users may assume searches stay local, because sensitive queries can be disclosed to a third party and credentials for that third party become operationally required.
This HTTP request transmits the query to api.openai.com together with authorization credentials, which is an external data transmission boundary. In the context of a search tool, this is risky because user input may contain secrets, internal project names, or regulated content that leaves the local environment.
echo "Generating embedding for query..."
# Generate embedding using OpenAI API
EMBEDDING_RESPONSE=$(curl -s -w "\n%{http_code}" \
-X POST \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
No suspicious patterns detected.