T09 · Insecure Skill Coding Practices
- Location
scripts/dex-cleanup.py:160- Finding
Bulk CRM Contact Archival Without Required Confirmation
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is mostly a disclosed Dex CRM integration, but it includes broad mutation authority and a bulk contact-archiving script that can change many CRM records without confirmation.
Install only if you are comfortable giving the agent a Dex API key that can read and modify CRM data. Use dry-run first for cleanup, review matched contacts manually, and avoid running the bulk archive script without an explicit confirmation or allowlist. Be especially careful with delete and update examples because they can permanently alter CRM history.
scripts/dex-cleanup.py:160Bulk CRM Contact Archival Without Required Confirmation
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
def api_get(path):
req = urllib.request.Request(f"{BASE}{path}", headers=HEADERS)
with urllib.request.urlopen(req) as resp:
return json.loads(resp.read())
def api_put(path, data):
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
def api_get(path):
req = urllib.request.Request(f"{BASE}{path}", headers=HEADERS)
with urllib.request.urlopen(req) as resp:
return json.loads(resp.read())
def api_put(path, data):
The declared description presents a broad personal CRM management skill focused on contact lookup, notes, and reminders. The supplied code instead performs a narrow, destructive/administrative cleanup task: enumerating contacts and archiving those classified as junk. That is a materially different primary purpose and includes an undeclared capability—bulk archiving contacts. While both involve Dex contacts and the same API key/resource, the behavior does not match the user-facing CRM functions described.
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
Copy the SKILL.md file to your Clawdbot skills directory:
cp SKILL.md ~/.clawdbot/skills/dex-crm/SKILL.md
# or for workspace installs:
cp SKILL.md ~/clawd/skills/dex-crm/SKILL.md
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
Copy the SKILL.md file to your Clawdbot skills directory:
cp SKILL.md ~/.clawdbot/skills/dex-crm/SKILL.md
# or for workspace installs:
cp SKILL.md ~/clawd/skills/dex-crm/SKILL.md
The manifest describes the skill as managing contacts, notes, and reminders, with enumerated use cases limited to searching/browsing contacts, adding notes, creating/checking reminders, and looking up contact details. The README adds materially broader behaviors: creating entirely new contacts and archiving existing contacts, which are write operations not reflected in the manifest’s stated use cases.
The manifest frames the skill around routine CRM tasks like searching contacts, adding notes, creating/checking reminders, and viewing details. The README documents an included script that automatically identifies and archives 'junk/newsletter contacts' in bulk, which is a separate cleanup/triage capability not described in the manifest.
The skill requires both network access and a secret from the environment (DEX_API_KEY) but does not declare any explicit tool scope or permissions boundary. That omission increases the chance the skill can be invoked with broader capabilities than intended, reducing reviewability and making misuse of the API key or remote operations harder to govern.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# List contacts (paginated)
curl -s -H "Content-Type: application/json" \
-H "x-hasura-dex-api-key: $DEX_API_KEY" \
"https://api.getdex.com/api/rest/contacts?limit=10&offset=0"
The manifest frames the skill as a manager for lookup/search, notes, and reminders, but the documented contact endpoints include create, update, and delete operations. This broader destructive capability is security-relevant because a user or agent may invoke the skill expecting read-oriented CRM assistance while the skill can also alter or permanently remove records.
The manifest advertises adding notes and creating/checking reminders, but the documented behavior also supports updating and deleting notes and reminders. Hidden destructive/editing functionality can lead to unintended modification or loss of CRM history if a caller assumes the skill is limited to additive actions.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
print("ERROR: DEX_API_KEY not set")
sys.exit(1)
BASE = "https://api.getdex.com/api/rest"
HEADERS = {
"Content-Type": "application/json",
"x-hasura-dex-api-key": API_KEY
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
print("ERROR: DEX_API_KEY not set")
sys.exit(1)
BASE = "https://api.getdex.com/api/rest"
HEADERS = {
"Content-Type": "application/json",
"x-hasura-dex-api-key": API_KEY
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
print("ERROR: DEX_API_KEY not set")
sys.exit(1)
BASE = "https://api.getdex.com/api/rest"
HEADERS = {
"Content-Type": "application/json",
"x-hasura-dex-api-key": API_KEY
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
print("ERROR: DEX_API_KEY not set")
sys.exit(1)
BASE = "https://api.getdex.com/api/rest"
HEADERS = {
"Content-Type": "application/json",
"x-hasura-dex-api-key": API_KEY
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
print("ERROR: DEX_API_KEY not set")
sys.exit(1)
BASE = "https://api.getdex.com/api/rest"
HEADERS = {
"Content-Type": "application/json",
"x-hasura-dex-api-key": API_KEY
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
print("ERROR: DEX_API_KEY not set")
sys.exit(1)
BASE = "https://api.getdex.com/api/rest"
HEADERS = {
"Content-Type": "application/json",
"x-hasura-dex-api-key": API_KEY
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
print("ERROR: DEX_API_KEY not set")
sys.exit(1)
BASE = "https://api.getdex.com/api/rest"
HEADERS = {
"Content-Type": "application/json",
"x-hasura-dex-api-key": API_KEY
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
print("ERROR: DEX_API_KEY not set")
sys.exit(1)
BASE = "https://api.getdex.com/api/rest"
HEADERS = {
"Content-Type": "application/json",
"x-hasura-dex-api-key": API_KEY
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
print("ERROR: DEX_API_KEY not set")
sys.exit(1)
BASE = "https://api.getdex.com/api/rest"
HEADERS = {
"Content-Type": "application/json",
"x-hasura-dex-api-key": API_KEY
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
print("ERROR: DEX_API_KEY not set")
sys.exit(1)
BASE = "https://api.getdex.com/api/rest"
HEADERS = {
"Content-Type": "application/json",
"x-hasura-dex-api-key": API_KEY
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
print("ERROR: DEX_API_KEY not set")
sys.exit(1)
BASE = "https://api.getdex.com/api/rest"
HEADERS = {
"Content-Type": "application/json",
"x-hasura-dex-api-key": API_KEY
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
print("ERROR: DEX_API_KEY not set")
sys.exit(1)
BASE = "https://api.getdex.com/api/rest"
HEADERS = {
"Content-Type": "application/json",
"x-hasura-dex-api-key": API_KEY
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
print("ERROR: DEX_API_KEY not set")
sys.exit(1)
BASE = "https://api.getdex.com/api/rest"
HEADERS = {
"Content-Type": "application/json",
"x-hasura-dex-api-key": API_KEY
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
print("ERROR: DEX_API_KEY not set")
sys.exit(1)
BASE = "https://api.getdex.com/api/rest"
HEADERS = {
"Content-Type": "application/json",
"x-hasura-dex-api-key": API_KEY
No suspicious patterns detected.