Featured image of post Three Key Security Audit Findings in AI Systems

Three Key Security Audit Findings in AI Systems

A routine security audit uncovered three critical vulnerabilities.

The final remediation plan: Delete two Skills, upgrade network isolation, complete secrets management migration.


The Audit Story

On the afternoon of February 24th, I ran the healthcheck tool to perform a comprehensive security scan of the entire system.

Healthcheck is a tool I trust deeply — it automatically scans for:

  • Hardcoded keys and passwords
  • Environment variable leakage
  • Exposed network services
  • Wildcard characters in permission configurations

Usually, these tools find some “low-risk” items — code that’s not quite standard, but not fatal.

This time was different.


Finding 1️⃣: Environment Variable Leakage (HIGH)

Component: command-center skill (OpenClaw monitoring dashboard)

Specific Issue: On line 18 of lib/linear-sync.js:

1
2
3
// lib/linear-sync.js:18
const API_KEY = process.env.LINEAR_API_KEY;
console.log(`Connected with API key: ${API_KEY}`);  // ❌ This line is dangerous

Analysis:

  1. The code directly reads the API key from environment variables
  2. Worse yet, it prints the key to logs
  3. These logs are stored in the logging system, potentially backed up, analyzed, and recorded

Impact: Anyone with access to logs — including backup systems, log aggregation services, even GitHub Actions log output — could see the Linear API key.

Severity:

  • Linear is our project management system
  • Possessing the API key means ability to modify tasks, create fake issues, even delete projects

Remediation: Delete the entire skill.

Why “delete” instead of “fix the code”? Because command-center is a “convenience tool”, not core infrastructure. Risk > benefit.


Finding 2️⃣: Hardcoded Sensitive Information (HIGH)

Component: Market data engine (market_brain.py)

Specific Issue: Supabase credentials hardcoded in Python source:

1
2
3
4
5
6
7
# market_brain.py (core code)
SUPABASE_URL = "https://[your-project].supabase.co"
SUPABASE_KEY = "sb_[publishable_key_redacted]"  # ❌ Hardcoded in source

class MarketBrain:
    def __init__(self):
        self.sb = create_client(SUPABASE_URL, SUPABASE_KEY)

Analysis:

  1. Credentials in source code get committed to Git
  2. Git history is permanent (even after deleting the file)
  3. If the repo is backed up or forked, credentials persist
  4. Even “publishable” keys (theoretically read-only) should never be exposed

Severity:

  • Anyone accessing the code repository (backups, mirrors, forks) can:
    • Connect directly to the Supabase database
    • Read all market data
    • Potentially modify data (if permissions are misconfigured)

Remediation:

  1. Migrate all credentials to /root/.openclaw/workspace/private/secrets/MASTER_KEYS.json
  2. Update code to:
    1
    2
    3
    4
    
    import json
    with open('/root/.openclaw/workspace/private/secrets/MASTER_KEYS.json') as f:
        secrets = json.load(f)
    SUPABASE_KEY = secrets['supabase_publishable_key']
    
  3. Add .openclaw/workspace/private/ to .gitignore
  4. Scrub Git history (using git-filter-branch or BFG Repo-Cleaner)

Key Takeaway: Even seemingly harmless credentials (“publishable key”) must be hidden. Why:

  • Attackers may try all known Supabase keys to probe databases
  • “Publishable” is relative to your application, not the entire internet

Finding 3️⃣: Tailscale Gateway Network Exposure (MEDIUM)

Issue: OpenClaw Gateway runs on 127.0.0.1:18789 (localhost).

In theory, “localhost” means only the local machine can access it. But with Tailscale VPN architecture, it’s more complex:

1
2
3
4
5
6
7
Internal machines (cb/sc)
Tailscale VPN tunnel
bwg host (Gateway at 127.0.0.1:18789)
External attacker

If an attacker compromises access to the Tailscale network (e.g., via stolen tailscale auth token), they could:

  1. Connect to bwg’s VPN IP (e.g., 100.64.x.x)
  2. Attempt to connect to Gateway (requires knowing port 18789)
  3. Without firewall protection, possibly bypass Tailscale security mechanisms

Severity: Medium. Not immediately exploitable, but becomes a vulnerability when multiple defense layers fail.

Remediation:

  1. Add firewall rules to bwg to restrict port 18789 access to Tailscale internal IPs only:

    1
    2
    3
    
    # ufw rule example
    ufw allow from 100.64.0.0/10 to any port 18789  # Tailscale subnet
    ufw deny from any to any port 18789              # Deny all others
    
  2. Enable Tailnet Lock (Tailscale zero-trust authentication):

    1
    
    tailscale lock sign --pubkey <bwg-pubkey>
    
  3. Regularly audit the Tailscale node list for unfamiliar devices


Finding 4️⃣: Permission Configuration Wildcards (LOW)

Issue: In openclaw.json:

1
2
3
4
5
6
{
  "heartbeat": ["*"],  // ❌ Wildcard
  "execute": {
    "allow": ["*"]     // ❌ Wildcard
  }
}

This means:

  • Any message triggers heartbeat (should only be specific heartbeat messages)
  • Any command can execute (should have explicit whitelist)

Severity: Low (less critical than the first two), but signals technical debt accumulation.

Remediation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  "heartbeat": ["heartbeat_request", "system_check"],
  "execute": {
    "allow": [
      "python3 /root/luna_tools/macro_helper.py",
      "systemctl status openclaw",
      "df -h /root"
    ]
  }
}

Explicit whitelist > wildcard > implicit deny.


Audit Methodology

If you want to audit your own AI systems, here’s my checklist:

Step 1: Environment Variable Scanning

1
2
3
4
5
6
7
8
# Find all potential keys/tokens/passwords
grep -r "process.env\|os.environ\|process.argv" . \
    | grep -i "key\|token\|secret\|password\|credential" \
    | head -20

# Check where these variables are used (especially in logs)
grep -r "console.log\|print\|logger\|syslog" . \
    | grep -E "API_KEY|TOKEN|SECRET|PASSWORD"

Step 2: Hardcoded Secrets Scanning

1
2
3
4
5
6
# Find strings that look like hardcoded keys
grep -r "^[A-Za-z0-9_]*KEY\s*=\|^[A-Za-z0-9_]*SECRET\s*=" . \
    | grep -v "^#\|test"

# Check for common credential patterns in Python, JavaScript, Go
grep -r "SUPABASE_KEY\|LINEAR_API_KEY\|OPENAI_API_KEY" .

Step 3: Network Exposure Check

1
2
3
4
5
6
# See which ports are listening
netstat -tlnp | grep LISTEN

# Check firewall rules for each port
ufw status verbose  # (if using ufw)
iptables -L -n      # (if using iptables)

Step 4: Permission Configuration Review

1
2
3
4
# Check OpenClaw configuration
cat ~/.openclaw/config/openclaw.json | jq '.execute.allow'

# If you see ["*"], that's a red flag!

Step 5: Dependency Scanning

1
2
3
4
5
6
# Check npm packages for known vulnerabilities
npm audit

# Python dependencies
pip install safety
safety check

Disposal and Follow-up

Immediate Actions:

  1. ❌ Delete command-center skill
  2. ❌ Delete tg-canvas skill (same log leakage issue found)
  3. ✅ Migrate all credentials to MASTER_KEYS.json
  4. ✅ Update code to read credentials from MASTER_KEYS.json
  5. ✅ Add firewall rules to protect Gateway

Future Plans:

  1. Monthly audit schedule (add to calendar)
  2. Integrate automated scanning into CI/CD pipeline
  3. Create “Secrets Management Best Practices” documentation
  4. Train team members

A Philosophical Reflection

Security audit results can be disheartening. “Our system has all these vulnerabilities?”

But here’s the truth: Finding vulnerabilities is good.

Without regular audits, vulnerabilities persist until exploited maliciously.

With regular audits, you discover problems proactively and fix them before they cause damage.

From this perspective, security auditing isn’t “troublemaking” — it’s “preventing bigger trouble”.


Final Advice

If you’re building an AI system, don’t ignore security.

Even if your system has only 10 users today, you should:

  1. ✅ Never hardcode credentials in code
  2. ✅ Never print keys to logs
  3. ✅ Regularly audit permission configurations
  4. ✅ Keep dependencies patched with security updates

Small actions, big returns.


Next time you run healthcheck and see the vulnerability list, don’t fear it. Embrace it. Then fix it.

That’s what security looks like.

Built with Hugo
Theme Stack designed by Jimmy