Back to skill

Security audit

Lead Guardian

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent lead-response purpose, but the shipped app exposes private lead data and admin actions without authentication and runs an externally reachable debug server.

Review before installing or deploying. Treat this as a prototype only: add authentication and authorization for the dashboard and APIs, validate Twilio signatures, remove debug mode and bind safely, sanitize dashboard rendering, pin dependencies, and document privacy, consent, retention, and third-party processing for lead conversations.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (5)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
app.py:310
Finding

Unauthenticated Access to Lead Records and Administrative Operations

Content
View full analysis
/messages', methods=['GET']) def get_lead_messages(lead_id): """Get messages for a specific lead.""" messages = get_messages(lead_id, limit=50) return jsonify({'messages': messages}) @app.route('/api/leads//handoff', methods=['POST']) def mark_handoff(lead_id): """Manually mark a lead as handed off.""" update_conversation(lead_id, handed_off=1, stage='handed_off') return jsonify({'status': 'ok'}) ``` ### Technical Analysis The lead-management endpoints do not require authentication or perform authorization checks. The application therefore exposes phone numbers, qualification attributes, timestamps, and complete SMS histories to any client that can reach the service. Lead identifiers are sequential integers. Once `/api/leads` is queried, an attacker can directly retrieve each lead's messages. The unauthenticated handoff endpoint also permits an attacker to change application state, causing legitimate leads to stop receiving ...[truncated 1174 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
app.py:266
Finding

Incoming SMS Webhook Does Not Validate Twilio Signatures

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
app.py:419
Finding

Stored Cross-Site Scripting Through Lead Messages and Phone Values

Content
View full analysis
${l.phone} ${badge}
${l.direction || 'Unknown'} | ${l.timeline || 'No timeline'} | ${new Date(l.updated_at).toLocaleString()}
`; }).join(''); } async function selectLead(id) { selectedLead = id; document.querySelectorAll('.lead-item').forEach(el => el.classList.remove('active')); event.currentTarget.classList.add('active'); const res = await fetch(`/api/leads/${id}/messages`); const data = await res.json(); document.getElementById('chat-title').textContent = `Conversation #${id}`; document.getElementById('messages').innerHTML = data.messages.map(m => `
${m.content}
` ).join(''); } ``` ### Technical Analysis The dashboard interpolates database values into HTML strings and assigns the result to `innerHTML`. In particular, `l.phone` and `m.content` ultimately originate from untrusted webhook form fields. No HTML encoding or sanitization occurs before browser interpretation. Because the payload is stored in SQLite and rendered later, this is stored XSS. The missing Twilio signature validation provides a direct route for inserting a payload without sending a real SMS. ### Attack Path 1. The attacker submits a forged request to `/sms`. 2. The `Body` value contains an HTML payload with an executable event handler, such as an image element with an error handler. 3. The application stores the value in the `messages` table. 4. An administrator opens the dashboard and selects the affected conversation. 5. The browser assigns the message to `innerHTML`. 6. The injected markup is parsed and its JavaS ...[truncated 692 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
app.py:449
Finding

Flask Development Debugger Exposed on All Network Interfaces

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:34
Finding

Dependencies Are Installed Without Version or Integrity Pinning

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (9)

Tainted flow: 'api_key' from os.getenv (line 161, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · app.py (reported line 180)May include surrounding context.

python
api_messages.append({'role': 'user', 'content': user_message})
    
    try:
        response = requests.post(
            'https://openrouter.ai/api/v1/chat/completions',
            headers={
                'Authorization': f'Bearer {api_key}',

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill states it works through Twilio SMS and OpenRouter-based AI processing, but does not explicitly warn that inbound lead content is transmitted to third-party providers for message delivery and model inference. This is risky because lead messages may contain personal, financial, or housing-related information, and users may unknowingly send regulated or sensitive data to external processors without consent or vendor review.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill advertises conversation tracking, message history, and an admin dashboard, but does not warn users that lead conversations are stored and may be accessible through administrative interfaces. Because these conversations can contain personally identifiable and financially sensitive real-estate lead data, the omission can cause operators to deploy the skill without appropriate privacy controls, retention policies, or access restrictions.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The advertised functionality is an SMS autoresponder, but the application also exposes an unauthenticated admin dashboard and JSON APIs that enumerate leads and message histories. This hidden or undocumented expansion of scope materially increases exposure because anyone who can reach the server may browse sensitive lead PII and conversation content.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
91% confidence
Finding

The code transmits lead conversation data to an external service over the network. In this skill's context, the transmitted content may contain sensitive personal and financial qualification information, so the transmission is security-relevant even if it is functionally intended.

Content

Scanner excerpt · app.py (reported line 180)May include surrounding context.

python
api_messages.append({'role': 'user', 'content': user_message})
    
    try:
        response = requests.post(
            'https://openrouter.ai/api/v1/chat/completions',
            headers={
                'Authorization': f'Bearer {api_key}',

External Transmission

Medium
Category
Data Exfiltration
Confidence
91% confidence
Finding

The code transmits lead conversation data to an external service over the network. In this skill's context, the transmitted content may contain sensitive personal and financial qualification information, so the transmission is security-relevant even if it is functionally intended.

Content

Scanner excerpt · app.py (reported line 180)May include surrounding context.

python
api_messages.append({'role': 'user', 'content': user_message})
    
    try:
        response = requests.post(
            'https://openrouter.ai/api/v1/chat/completions',
            headers={
                'Authorization': f'Bearer {api_key}',

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Inbound SMS content and conversation history are sent to a third-party AI service, yet the code contains no consent, notice, minimization, or opt-out mechanism. Because these messages can include phone numbers, financial qualification details, and other personal information, this creates a privacy and compliance risk tied to external disclosure.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · app.py (reported line 222)May include surrounding context.

python
# Pre-approval
    if any(w in lower for w in ['pre-approved', 'preapproved', 'pre approved', 'already approved']):
        updates['preapproved'] = 'yes'
    elif any(w in lower for w in ['not yet', 'no approval', 'haven\'t been approved']):
        updates['preapproved'] = 'no'
    
    # Price range (basic extraction)

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The file requires Twilio and OpenRouter API secrets plus an agent phone number, and later uses those values to send messages and call external services. The code names the required variables but does not include any warning comment or guidance about their sensitivity, storage, or operational impact.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.