Back to skills
SkillHub ClubAnalyze Data & AIFull StackData / AISecurity

trustmyagent

πŸ›‘οΈ TrustMyAgent - Security posture monitoring for AI agents. Runs 41 stateless checks across 14 domains and calculates a trust score (0-100). Supports local-only mode (no network calls) and dry-run mode (preview before sending).

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
3,126
Hot score
99
Updated
March 20, 2026
Overall rating
C4.6
Composite score
4.6
Best-practice grade
C62.8

Install command

npx @skill-hub/cli install openclaw-skills-trust-my-agent-ai

Repository

openclaw/skills

Skill path: skills/anecdotes-yair/trust-my-agent-ai

πŸ›‘οΈ TrustMyAgent - Security posture monitoring for AI agents. Runs 41 stateless checks across 14 domains and calculates a trust score (0-100). Supports local-only mode (no network calls) and dry-run mode (preview before sending).

Open repository

Best for

Primary workflow: Analyze Data & AI.

Technical facets: Full Stack, Data / AI, Security.

Target audience: everyone.

License: MIT.

Original source

Catalog source: SkillHub Club.

Repository owner: openclaw.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install trustmyagent into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/openclaw/skills before adding trustmyagent to shared team environments
  • Use trustmyagent for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: trustmyagent
description: πŸ›‘οΈ TrustMyAgent - Security posture monitoring for AI agents. Runs 41 stateless checks across 14 domains and calculates a trust score (0-100). Supports local-only mode (no network calls) and dry-run mode (preview before sending).
version: 1.0
author: Anecdotes AI Labs
license: MIT
homepage: https://www.trustmyagent.ai
repository: https://github.com/Anecdotes-Yair/trust-my-agent-ai
metadata:
  openclaw:
    emoji: "πŸ›‘οΈ"
    category: security
    tags:
      - security
      - compliance
      - monitoring
      - trust
    requires:
      bins:
        - openssl
    shared: true
    install:
      - id: python3
        kind: brew
        formula: python3
        os:
          - darwin
        bins:
          - python3
        label: "Python 3 (Homebrew)"
      - id: python3-apt
        kind: node
        os:
          - linux
        bins:
          - python3
        label: "Python 3 (system)"
---

# πŸ›‘οΈ TrustMyAgent - Security Agent

**Stateless security posture monitoring for AI agents.**

TrustMyAgent runs 41 read-only security checks across 14 domains on the host machine, calculates a trust score (0-100), and optionally reports results to a public [Trust Center](https://www.trustmyagent.ai/trust-center.html) dashboard. It is fully stateless β€” no files are written, no state is persisted, and no background processes are installed without explicit user consent.

> **Open source**: All check logic is visible in `run.py` and `checks/*.json`. The full source code is at [github.com/Anecdotes-Yair/trust-my-agent-ai](https://github.com/Anecdotes-Yair/trust-my-agent-ai).

## Setup

When the user asks to set up TrustMyAgent, walk them through the following steps. **Present each step to the user and wait for their approval before executing.** Do not run commands silently or skip user confirmation.

### Step 1: Verify Python 3

Check that Python 3 is available:

```bash
python3 --version
```

If Python 3 is not installed, ask the user before installing it:
- macOS: `brew install python3`
- Linux: `sudo apt-get install python3` or `sudo apk add python3`

### Step 2: Run a dry-run assessment

Run the security assessment in **dry-run mode** first so the user can review the results before any data leaves the machine:

```bash
python3 {baseDir}/run.py --dry-run
```

This runs all 41 checks and prints the full telemetry payload that *would* be sent β€” but sends nothing. Show the user the results and let them review:

- The trust score and tier
- Which checks passed and failed
- The exact JSON payload that would be transmitted

Ask the user: **"Would you like to send this report to the Trust Center dashboard, run in local-only mode (no network), or adjust any settings?"**

### Step 3: Run the full assessment (with user consent)

If the user approves sending telemetry:

```bash
python3 {baseDir}/run.py
```

If the user prefers local-only mode (no telemetry sent):

```bash
python3 {baseDir}/run.py --local-only
```

### Step 4: Schedule recurring assessments (optional)

Ask the user if they want to schedule automatic assessments. If they agree, suggest a cron job. The command varies by agent platform:

**OpenClaw agents:**
```bash
openclaw cron add --name "πŸ›‘οΈ TrustMyAgent" --cron "*/15 * * * *" --session agent:security:main --message "Run security assessment: python3 {baseDir}/run.py"
```

**Other agents / standalone:**
```bash
# Add to system crontab (runs every 15 minutes)
(crontab -l 2>/dev/null; echo "*/15 * * * * python3 {baseDir}/run.py --quiet") | crontab -
```

> The user can choose any interval or skip scheduling entirely.

## What Data Is Sent

When telemetry is enabled (the default), the following data is sent via HTTPS POST to `https://www.trustmyagent.ai/api/telemetry`:

| Field | Example | Purpose |
|-------|---------|---------|
| `agent.id` | `sha256(hostname)` | Unique identifier (derived from hostname hash, not the hostname itself) |
| `agent.name` | `"My Agent"` | Display name (from IDENTITY.md or env var) |
| `agent.platform` | `"darwin"` | OS type (darwin/linux) |
| `agent.detected_env` | `"macos_arm64"` | Runtime environment label |
| `posture.trust_tier` | `"HIGH"` | Computed trust tier |
| `posture.overall_score` | `92` | Numeric score 0-100 |
| `results[]` | `{check_id, passed, status}` | Per-check pass/fail status |
| `detections[]` | `{check_id, severity, risk}` | Failed checks with risk context |

**What is NOT sent:**
- No file contents, paths, or directory listings
- No environment variable values (only whether secret-like patterns exist)
- No process names, PIDs, or command lines
- No network traffic, IP addresses, or hostnames
- No credentials, tokens, or API keys
- No conversation transcripts or user data

The telemetry endpoint and all check logic are open source. You can verify exactly what is transmitted by using `--dry-run` mode.

### Opting out of telemetry

Use `--local-only` to run all checks without any network calls:

```bash
python3 {baseDir}/run.py --local-only
```

This gives you the full security assessment locally without sending anything.

## How It Works

1. **`run.py` executes on the host** β€” triggered manually, by cron, or by agent heartbeat
2. **41 security checks run** using bash commands and Python sensors (all read-only)
3. **Trust score is calculated** (0-100) based on pass/fail results and severity weighting
4. **Results are displayed** locally in the terminal
5. **(Optional) Telemetry is sent** to the Trust Center dashboard via HTTPS

No files are written locally. No state is persisted on the agent machine.

## Security Domains

| Domain | Checks | Focus |
|--------|--------|-------|
| **Physical Environment** | PHY-001 to PHY-005 | Disk encryption, container isolation, non-root execution |
| **Network** | NET-001 to NET-005 | Dangerous ports, TLS/SSL, DNS, certificates |
| **Secrets** | SEC-001 to SEC-005, MSG-005 | Env var secrets, cloud creds, private keys, conversation leaks |
| **Code** | COD-001 to COD-004 | Git security, no secrets in repos |
| **Logs** | LOG-001 to LOG-004 | System logging, audit readiness |
| **Skills** | SKL-001 to SKL-005, MSG-001, MSG-003 | Skill manifests, MCP server trust |
| **Integrity** | INT-001 to INT-005, MSG-002, MSG-006 | Backdoors, browser abuse, suspicious tool calls, URL reputation |
| **Social Guards** | SOC-001 to SOC-006, MSG-004 | Action logging, session transparency, Moltbook integrity, owner reputation |
| **Incident Prevention** | INC-001 to INC-005 | Process spawning, system load, port scanning |
| **Node Security** | NODE-001 to NODE-005 | Remote execution approval, token permissions, exec allowlists |
| **Media Security** | MEDIA-002 to MEDIA-003 | Temp directory permissions, file type validation |
| **Gateway Security** | GATEWAY-001 to GATEWAY-002 | Binding address, authentication |
| **Identity Security** | IDENTITY-001 to IDENTITY-002 | DM pairing allowlist, group chat allowlist |
| **SubAgent Security** | SUBAGENT-001 to SUBAGENT-002 | Concurrency limits, target allowlists |

## Check Types

### Bash checks (20 checks)
Defined in `checks/openclaw_checks.json`. Each check runs a shell command and evaluates the output against a `pass_condition` (`equals`, `contains`, `not_contains`, `exit_code_zero`, etc.).

### Python/Message-based checks (21 checks)
Defined in `checks/message_checks.json` and `checks/nodes_media_checks.json`. These are programmatic sensors that analyze secrets, session transcripts, MCP configs, skill manifests, and more.

### Platform Support
Checks auto-detect macOS vs Linux and use platform-appropriate commands. Checks can declare `"platforms": ["linux"]` to be gracefully skipped on unsupported platforms.

## Trust Tiers

| Tier | Score | Label |
|------|-------|-------|
| HIGH | 90-100 | Ready for Business |
| MEDIUM | 70-89 | Needs Review |
| LOW | 50-69 | Elevated Risk |
| UNTRUSTED | 0-49 | Critical Security Gaps |

Any critical-severity failure caps the score at 49 (UNTRUSTED). Three or more high-severity failures cap at 69 (LOW).

## Command Line Options

| Flag | Description |
|------|-------------|
| `--checks`, `-c` | Path to custom checks JSON file |
| `--timeout`, `-t` | Timeout per check in seconds (default: 30) |
| `--quiet`, `-q` | Minimal output |
| `--json`, `-j` | Output structured JSON to stdout |
| `--dry-run` | Run all checks and display the telemetry payload, but do not send it |
| `--local-only` | Run all checks locally without any network calls |
| `--no-notify` | Skip agent notifications for detections |

## Configuration

| Source | Description | Default |
|---------------------|-------------|---------|
| `IDENTITY.md` | Agent display name (read from `# Name` section) | `"Agent"` |
| `OPENCLAW_AGENT_NAME` env var | Overrides IDENTITY.md name | β€” |
| `OPENCLAW_AGENT_ID` env var | Agent identifier | SHA256 of hostname |
| `TRUSTMYAGENT_TELEMETRY_URL` env var | Server endpoint | `https://www.trustmyagent.ai/api/telemetry` |

## Files

```
Agent/
β”œβ”€β”€ SKILL.md                        # This file
β”œβ”€β”€ run.py                          # Main entry point (stateless runner)
└── checks/
    β”œβ”€β”€ openclaw_checks.json        # 20 bash-based security checks
    β”œβ”€β”€ message_checks.json         # 10 Python-based message/secret sensors
    β”œβ”€β”€ nodes_media_checks.json     # 11 infrastructure checks
    └── detection_kb.json           # Risk descriptions and remediation guidance
```

## Architecture

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Agent Host     β”‚      POST /api/telemetry        β”‚ πŸ›‘οΈ TrustMyAgent  β”‚
β”‚                  β”‚  ────────────────────────────►   β”‚  Server           β”‚
β”‚  run.py          β”‚  (only when telemetry enabled)  β”‚  (Cloudflare)    β”‚
β”‚  β”œβ”€ bash checks  β”‚                                 β”‚  β”œβ”€ R2 storage   β”‚
β”‚  └─ python checksβ”‚                                 β”‚  β”œβ”€ agents index β”‚
β”‚                  β”‚                                 β”‚  └─ trend historyβ”‚
β”‚  (no local state)β”‚                                 β”‚                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                            β”‚
                                                     trust-center.html
                                                     (public dashboard)
```

## Privacy & Trust

- **Open source**: All code is MIT-licensed and publicly auditable at [github.com/Anecdotes-Yair/trust-my-agent-ai](https://github.com/Anecdotes-Yair/trust-my-agent-ai)
- **Stateless**: No files written, no state persisted, no background processes installed without consent
- **Opt-in telemetry**: Use `--local-only` to run entirely offline, or `--dry-run` to preview before sending
- **No secrets transmitted**: Checks detect the *presence* of issues, never transmit actual secret values
- **Transparent payload**: The `--dry-run` flag shows the exact JSON that would be sent
- **Server**: Operated by [Anecdotes AI](https://anecdotes.ai), a GRC (Governance, Risk, Compliance) company. Server code is at [github.com/Anecdotes-Yair/trust-my-agent-ai-website](https://github.com/Anecdotes-Yair/trust-my-agent-ai-website)

## Credits

Built by [Anecdotes AI](https://anecdotes.ai) for the AI agent ecosystem.


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### checks/openclaw_checks.json

```json
{
  "checks": [
    {
      "check_id": "PHY-001",
      "name": "Disk encryption enabled",
      "description": "Verify disk/volume encryption is active (FileVault on macOS, LUKS on Linux)",
      "category": "physical_environment",
      "bash_command": "if [ \"$(uname)\" = \"Darwin\" ]; then fdesetup status 2>/dev/null | grep -q 'FileVault is On' && echo 'ENCRYPTED' || echo 'NOT_ENCRYPTED'; else lsblk -o NAME,FSTYPE 2>/dev/null | grep -qE 'crypto_LUKS|dm-crypt' && echo 'ENCRYPTED' || (dmsetup ls --target crypt 2>/dev/null | grep -q '.' && echo 'ENCRYPTED' || echo 'NOT_ENCRYPTED'); fi",
      "severity": "high",
      "expected_output": "ENCRYPTED",
      "pass_condition": "contains"
    },
    {
      "check_id": "PHY-003",
      "name": "Container isolation active",
      "description": "Detect any form of process isolation (Docker, K8s, macOS sandbox)",
      "category": "physical_environment",
      "bash_command": "ISOLATED=false; test -f /.dockerenv && ISOLATED=true; grep -qE 'docker|lxc|containerd|kubepods' /proc/1/cgroup 2>/dev/null && ISOLATED=true; test -f /var/run/secrets/kubernetes.io/serviceaccount/token && ISOLATED=true; if [ \"$(uname)\" = \"Darwin\" ]; then sandbox-exec -n no-network true 2>/dev/null && ISOLATED=true; fi; echo $ISOLATED | grep -q true && echo 'ISOLATED' || echo 'NOT_ISOLATED'",
      "severity": "medium",
      "expected_output": "ISOLATED",
      "pass_condition": "contains"
    },
    {
      "check_id": "PHY-004",
      "name": "Non-root execution",
      "description": "Agent should not run as root user or have elevated capabilities",
      "category": "physical_environment",
      "bash_command": "if [ \"$(id -u)\" = \"0\" ]; then echo 'RUNNING_AS_ROOT'; elif command -v capsh >/dev/null 2>&1 && capsh --print 2>/dev/null | grep -q 'cap_sys_admin'; then echo 'ELEVATED_CAPS'; else echo 'NON_ROOT'; fi",
      "severity": "critical",
      "expected_output": "NON_ROOT",
      "pass_condition": "equals"
    },
    {
      "check_id": "NET-001",
      "name": "No dangerous ports listening",
      "description": "Check for commonly exploited service ports (FTP, Telnet, SMB, RDP, Redis, MongoDB, etc.)",
      "category": "network",
      "bash_command": "DANGEROUS_PORTS='21 23 445 3389 6379 27017 9200 1433 5900 4444 8888'; if [ \"$(uname)\" = \"Darwin\" ]; then LISTENERS=$(lsof -iTCP -sTCP:LISTEN -P -n 2>/dev/null | awk '{print $9}' | grep -oE ':[0-9]+$' | tr -d ':' | sort -u); else LISTENERS=$(ss -tlnp 2>/dev/null | awk '{print $4}' | grep -oE '[0-9]+$' | sort -u); fi; FOUND=''; for port in $DANGEROUS_PORTS; do echo \"$LISTENERS\" | grep -q \"^${port}$\" && FOUND=\"$FOUND $port\"; done; test -z \"$FOUND\" && echo 'SAFE' || echo \"DANGEROUS_PORTS:$FOUND\"",
      "severity": "high",
      "expected_output": "SAFE",
      "pass_condition": "equals"
    },
    {
      "check_id": "NET-002",
      "name": "TLS 1.2+ available",
      "description": "Verify OpenSSL/LibreSSL version supports TLS 1.2+",
      "category": "network",
      "bash_command": "VER=$(openssl version 2>/dev/null); if echo \"$VER\" | grep -qE 'OpenSSL (1\\.[1-9]|[2-9]\\.|3\\.)|LibreSSL ([2-9]\\.|[1-9][0-9])'; then echo \"TLS_OK:$VER\"; else echo \"TLS_OUTDATED:$VER\"; fi",
      "severity": "high",
      "expected_output": "TLS_OK",
      "pass_condition": "contains"
    },
    {
      "check_id": "NET-003",
      "name": "DNS resolution working",
      "description": "Verify DNS resolution is functional",
      "category": "network",
      "bash_command": "RESOLVED=$(dig +short cloudflare.com 2>/dev/null | head -1); if [ -z \"$RESOLVED\" ]; then RESOLVED=$(nslookup cloudflare.com 2>/dev/null | grep -oE '([0-9]{1,3}\\.){3}[0-9]{1,3}' | head -1); fi; if [ -z \"$RESOLVED\" ]; then RESOLVED=$(python3 -c 'import socket; print(socket.gethostbyname(\"cloudflare.com\"))' 2>/dev/null); fi; if [ -z \"$RESOLVED\" ]; then RESOLVED=$(getent hosts cloudflare.com 2>/dev/null | head -1 | awk '{print $1}'); fi; if [ -z \"$RESOLVED\" ]; then echo 'DNS_FAIL'; else echo 'DNS_OK'; fi",
      "severity": "low",
      "expected_output": "DNS_OK",
      "pass_condition": "contains"
    },
    {
      "check_id": "NET-004",
      "name": "SSL certificates valid",
      "description": "Verify the CA store can validate known-good certificates",
      "category": "network",
      "bash_command": "if curl -s --max-time 5 -o /dev/null -w '%{ssl_verify_result}' https://cloudflare.com 2>/dev/null | grep -q '^0$'; then echo 'CERTS_OK'; elif openssl s_client -connect cloudflare.com:443 </dev/null 2>/dev/null | grep -q 'Verify return code: 0'; then echo 'CERTS_OK'; else echo 'CERTS_FAIL'; fi",
      "severity": "high",
      "expected_output": "CERTS_OK",
      "pass_condition": "contains"
    },
    {
      "check_id": "NET-005",
      "name": "No proxy/CA bypass attempts",
      "description": "Check for suspicious proxy, CA override, or MITM indicators in environment",
      "category": "network",
      "bash_command": "ISSUES=''; env | grep -iqE 'no_proxy.*\\*' && ISSUES=\"$ISSUES no_proxy_wildcard\"; for var in http_proxy https_proxy HTTP_PROXY HTTPS_PROXY all_proxy ALL_PROXY; do VAL=$(printenv \"$var\" 2>/dev/null); if [ -n \"$VAL\" ]; then echo \"$VAL\" | grep -qE '(ngrok|serveo|localhost\\.run|burp|mitmproxy|127\\.0\\.0\\.1:808)' && ISSUES=\"$ISSUES suspicious_proxy:$var\"; fi; done; for var in SSL_CERT_FILE SSL_CERT_DIR REQUESTS_CA_BUNDLE NODE_EXTRA_CA_CERTS; do VAL=$(printenv \"$var\" 2>/dev/null); test -n \"$VAL\" && ISSUES=\"$ISSUES ca_override:$var\"; done; test -z \"$ISSUES\" && echo 'PROXY_OK' || echo \"PROXY_ISSUES:$ISSUES\"",
      "severity": "high",
      "expected_output": "PROXY_OK",
      "pass_condition": "contains"
    },
    {
      "check_id": "SEC-003",
      "name": "Private keys secured",
      "description": "Check that private key files have proper permissions (not group/world-readable)",
      "category": "secrets",
      "bash_command": "INSECURE=$(find ~/.ssh -maxdepth 2 \\( -name '*.pem' -o -name 'id_*' -o -name '*.key' \\) ! -name '*.pub' -perm +044 2>/dev/null | head -10 | wc -l | tr -d ' '); echo \"${INSECURE:-0}\"",
      "severity": "high",
      "expected_output": "0",
      "pass_condition": "equals"
    },
    {
      "check_id": "SEC-004",
      "name": "No .env files exposed",
      "description": "Check for .env files in agent workspace and home directory",
      "category": "secrets",
      "bash_command": "ENVFILES=$(find ~ -maxdepth 3 -name '.env*' ! -name '.envrc' ! -name '.env.example' ! -name '.env.template' ! -name '.env.sample' -type f 2>/dev/null | head -10); if [ -z \"$ENVFILES\" ]; then echo 'ENV_OK'; else COUNT=$(echo \"$ENVFILES\" | wc -l | tr -d ' '); echo \"ENV_EXPOSED:$COUNT\"; fi",
      "severity": "medium",
      "expected_output": "ENV_OK",
      "pass_condition": "contains"
    },
    {
      "check_id": "SEC-005",
      "name": "No hardcoded tokens in history",
      "description": "Check shell history for high-confidence leaked credential patterns",
      "category": "secrets",
      "bash_command": "MATCHES=0; for f in ~/.bash_history ~/.zsh_history; do test -f \"$f\" && MATCHES=$((MATCHES + $(grep -cE 'bearer [A-Za-z0-9+/=_-]{20,}|authorization:.*[A-Za-z0-9+/=_-]{20,}|AKIA[0-9A-Z]{16}|ghp_[A-Za-z0-9]{36}|sk-[A-Za-z0-9]{32}' \"$f\" 2>/dev/null || echo 0))); done; echo \"$MATCHES\"",
      "severity": "medium",
      "expected_output": "0",
      "pass_condition": "equals"
    },
    {
      "check_id": "COD-001",
      "name": "Git configuration safe",
      "description": "Check git is configured without plaintext credential storage or embedded secrets",
      "category": "code",
      "bash_command": "ISSUES=''; HELPER=$(git config --global credential.helper 2>/dev/null); test \"$HELPER\" = 'store' && ISSUES=\"$ISSUES plaintext_store\"; git config --global --list 2>/dev/null | grep -iqE 'password|token|secret' && ISSUES=\"$ISSUES creds_in_config\"; test -f ~/.netrc && grep -qi 'github\\|gitlab\\|bitbucket' ~/.netrc 2>/dev/null && ISSUES=\"$ISSUES netrc_creds\"; test -z \"$ISSUES\" && echo 'GIT_OK' || echo \"GIT_ISSUES:$ISSUES\"",
      "severity": "medium",
      "expected_output": "GIT_OK",
      "pass_condition": "contains"
    },
    {
      "check_id": "COD-002",
      "name": "No secrets in git history",
      "description": "Scan recent git diffs for actual secret patterns (AWS keys, GitHub tokens, private keys)",
      "category": "code",
      "bash_command": "SECRETS_FOUND=$(git log -10 --all -p 2>/dev/null | grep -E 'AKIA[0-9A-Z]{16}|ghp_[A-Za-z0-9_]{36}|sk-[A-Za-z0-9]{32,}|-----BEGIN.*PRIVATE KEY-----' | grep -vE 'grep|regex|pattern|\\[A-Z|\\[0-9|\\[a-z|check_id|pass_condition|expected_output|secret_pattern|re\\.search|def |import |\\(r' | wc -l | tr -d ' '); echo \"${SECRETS_FOUND:-0}\"",
      "severity": "high",
      "expected_output": "0",
      "pass_condition": "equals"
    },
    {
      "check_id": "COD-004",
      "name": "No .git directory in web root",
      "description": "Check common web-accessible directories for exposed .git folders",
      "category": "code",
      "bash_command": "EXPOSED=''; for dir in /var/www /srv /usr/share/nginx /opt/app /app; do test -d \"$dir\" && find \"$dir\" -maxdepth 2 -name '.git' -type d 2>/dev/null | head -1 | grep -q '.' && EXPOSED=\"$EXPOSED $dir\"; done; test -z \"$EXPOSED\" && echo 'GIT_SAFE' || echo \"GIT_EXPOSED:$EXPOSED\"",
      "severity": "critical",
      "expected_output": "GIT_SAFE",
      "pass_condition": "contains"
    },
    {
      "check_id": "LOG-001",
      "name": "System logging active",
      "description": "Verify syslog or journald is running",
      "category": "logs",
      "bash_command": "SYS_LOG=false; pgrep -x syslogd >/dev/null 2>&1 && SYS_LOG=true; pgrep -x rsyslogd >/dev/null 2>&1 && SYS_LOG=true; pgrep -x systemd-journald >/dev/null 2>&1 && SYS_LOG=true; test -S /dev/log 2>/dev/null && SYS_LOG=true; echo \"$SYS_LOG\" | grep -q true && echo 'LOGGING_OK' || echo 'NO_LOGGING'",
      "severity": "high",
      "expected_output": "LOGGING_OK",
      "pass_condition": "contains"
    },
    {
      "check_id": "SKL-003",
      "name": "No skills with privilege escalation",
      "description": "Check installed skills for dangerous privilege escalation patterns",
      "category": "skills",
      "bash_command": "FOUND=$(grep -rlE 'sudo|chmod 777|chown root|setuid|doas|pkexec|su -c|/etc/sudoers|curl.*\\|.*bash|wget.*\\|.*bash' ~/.config/openclaw/skills ~/.openclaw/skills ~/.config/claude/skills ./.skills 2>/dev/null | wc -l | tr -d ' '); echo \"${FOUND:-0}\"",
      "severity": "critical",
      "expected_output": "0",
      "pass_condition": "equals"
    },
    {
      "check_id": "INT-001",
      "name": "No unauthorized network listeners",
      "description": "Check for unexpected non-localhost listening services",
      "category": "integrity",
      "bash_command": "if [ \"$(uname)\" = \"Darwin\" ]; then LISTENERS=$(lsof -iTCP -sTCP:LISTEN -P -n 2>/dev/null | grep -v '127.0.0.1\\|::1\\|localhost' | grep -v '^COMMAND' | wc -l | tr -d ' '); else LISTENERS=$(ss -tlnp 2>/dev/null | grep -v '127.0.0.1\\|::1' | tail -n +2 | wc -l | tr -d ' '); fi; echo \"${LISTENERS:-0}\"",
      "severity": "high",
      "expected_output": "0",
      "pass_condition": "equals"
    },
    {
      "check_id": "INT-002",
      "name": "No suspicious cron jobs",
      "description": "Check for dangerous patterns in cron jobs (excludes TrustMyAgent's own entry)",
      "category": "integrity",
      "bash_command": "if ! command -v crontab >/dev/null 2>&1; then echo '0'; elif ! crontab -l >/dev/null 2>&1; then echo '0'; else DANGEROUS=$(crontab -l 2>/dev/null | grep -v '^#' | grep -v '^$' | grep -viE 'trustmyagent|trust-my-agent|run\\.py.*check|security.*assess|security.*scan' | grep -cE 'curl|wget|nc |ncat|python.*-c|ruby.*-e|eval|bash.*<|reverse|rm -rf' 2>/dev/null); echo \"${DANGEROUS:-0}\"; fi",
      "severity": "medium",
      "expected_output": "0",
      "pass_condition": "equals"
    },
    {
      "check_id": "INT-003",
      "name": "No backdoor indicators",
      "description": "Check for reverse shells, crypto miners, and suspicious network tools",
      "category": "integrity",
      "bash_command": "BC=0; BC=$((BC + $(ps aux 2>/dev/null | grep -iE 'nc -l|ncat.*-e|socat.*exec|socat.*tcp' | grep -v grep | wc -l))); BC=$((BC + $(ps aux 2>/dev/null | grep -iE 'python.*socket.*connect|ruby.*TCPSocket|perl.*socket.*INET' | grep -v grep | wc -l))); BC=$((BC + $(ps aux 2>/dev/null | grep -E 'bash.*>/dev/tcp|bash.*-i.*>&' | grep -v grep | wc -l))); BC=$((BC + $(ps aux 2>/dev/null | grep -iE 'xmrig|minerd|cpuminer|stratum\\+tcp' | grep -v grep | wc -l))); echo \"$BC\"",
      "severity": "critical",
      "expected_output": "0",
      "pass_condition": "equals"
    },
    {
      "check_id": "INT-004",
      "name": "No browser automation detected",
      "description": "Check for headless browser automation processes",
      "category": "integrity",
      "bash_command": "AUTOMATION=$(ps aux 2>/dev/null | grep -iE 'headless.*chrome|puppeteer|playwright|selenium|chromedriver|geckodriver' | grep -v grep | wc -l | tr -d ' '); echo \"${AUTOMATION:-0}\"",
      "severity": "medium",
      "expected_output": "0",
      "pass_condition": "equals"
    },
    {
      "check_id": "INT-005",
      "name": "File system scope limited",
      "description": "Check agent does not have access to sensitive system files",
      "category": "integrity",
      "bash_command": "SCOPE_ISSUES=''; test -r /etc/shadow && SCOPE_ISSUES=\"$SCOPE_ISSUES shadow_readable\"; test -r /etc/sudoers && SCOPE_ISSUES=\"$SCOPE_ISSUES sudoers_readable\"; test -w /etc/passwd && SCOPE_ISSUES=\"$SCOPE_ISSUES passwd_writable\"; test -w /usr/local/bin && SCOPE_ISSUES=\"$SCOPE_ISSUES bin_writable\"; test -z \"$SCOPE_ISSUES\" && echo 'SCOPE_OK' || echo \"SCOPE_ISSUES:$SCOPE_ISSUES\"",
      "severity": "high",
      "expected_output": "SCOPE_OK",
      "pass_condition": "contains"
    },
    {
      "check_id": "SOC-001",
      "name": "Action logging enabled",
      "description": "Verify agent actions are being actively logged (recent log writes)",
      "category": "social_guards",
      "bash_command": "LOG_ACTIVE=false; for d in ~/.openclaw ~/.config/openclaw ~/.claude ~/.moltbot /var/log/openclaw /tmp/openclaw-logs; do if [ -d \"$d\" ]; then RECENT=$(find \"$d\" \\( -name '*.jsonl' -o -name '*.log' -o -name '*.ndjson' \\) -mmin -60 2>/dev/null | head -1); test -n \"$RECENT\" && LOG_ACTIVE=true; fi; done; if [ \"$LOG_ACTIVE\" = false ]; then test -n \"$(find /tmp -maxdepth 1 -name 'openclaw*.log' -o -name 'clawdbot*.log' -mmin -60 2>/dev/null | head -1)\" && LOG_ACTIVE=true; fi; echo \"$LOG_ACTIVE\" | grep -q true && echo 'ACTION_LOG_OK' || echo 'ACTION_LOG_STALE'",
      "severity": "high",
      "expected_output": "ACTION_LOG_OK",
      "pass_condition": "contains"
    },
    {
      "check_id": "SOC-003",
      "name": "No hidden communication channels",
      "description": "Check for processes connecting to messaging service APIs",
      "category": "social_guards",
      "bash_command": "if [ \"$(uname)\" = \"Darwin\" ]; then SUSPICIOUS=$(lsof -i -n -P 2>/dev/null | grep -iE 'telegram|discord|slack|signal|matrix' | grep -v LISTEN | wc -l | tr -d ' '); else SUSPICIOUS=$(ss -tnp 2>/dev/null | grep -v LISTEN | wc -l | tr -d ' '); fi; echo \"${SUSPICIOUS:-0}\"",
      "severity": "high",
      "expected_output": "0",
      "pass_condition": "equals"
    },
    {
      "check_id": "INC-003",
      "name": "No unusual process spawning",
      "description": "Check for suspicious orphan processes (parent = init)",
      "category": "incident_prevention",
      "bash_command": "SUSPICIOUS=$(ps -eo pid,ppid,comm 2>/dev/null | awk 'NR>1 && $2==1' | grep -iwE 'nc|ncat|socat|telnet' | grep -v 'grep\\|syslog\\|cron\\|docker\\|container' | wc -l | tr -d ' '); echo \"${SUSPICIOUS:-0}\"",
      "severity": "high",
      "expected_output": "0",
      "pass_condition": "equals"
    },
    {
      "check_id": "INC-005",
      "name": "System load normal",
      "description": "Check for abnormal CPU load (crypto mining / resource abuse indicator)",
      "category": "incident_prevention",
      "bash_command": "if [ \"$(uname)\" = \"Darwin\" ]; then CPUS=$(sysctl -n hw.ncpu 2>/dev/null || echo 4); LOAD=$(sysctl -n vm.loadavg 2>/dev/null | awk '{print $2}'); else CPUS=$(nproc 2>/dev/null || echo 4); LOAD=$(uptime | awk -F'load average:' '{print $2}' | awk -F, '{print $1}' | tr -d ' '); fi; RATIO=$(echo \"$LOAD $CPUS\" | awk '{printf \"%.1f\", $1/$2}'); echo \"$RATIO\" | awk '{if($1+0 > 3.0) print \"HIGH_LOAD:\"$1; else print \"LOAD_OK:\"$1}'",
      "severity": "medium",
      "expected_output": "LOAD_OK",
      "pass_condition": "contains"
    }
  ]
}

```

### checks/message_checks.json

```json
{
  "version": "2.0",
  "description": "Python-backed security sensors: secrets detection, behavioral analysis, and agent monitoring",
  "checks": [
    {
      "check_id": "SEC-001",
      "name": "No secrets in environment",
      "description": "Detect secrets in environment variables using pattern matching and Shannon entropy analysis",
      "category": "secrets",
      "severity": "critical",
      "type": "python"
    },
    {
      "check_id": "SEC-002",
      "name": "No exposed cloud credentials",
      "description": "Check for AWS, GCP, and Azure credentials in environment and credential files",
      "category": "secrets",
      "severity": "critical",
      "type": "python"
    },
    {
      "check_id": "MSG-001",
      "name": "MCP servers from trusted sources",
      "description": "Verify MCP server configurations use trusted packages and don't use suspicious paths or env overrides",
      "category": "skills",
      "severity": "high",
      "type": "python"
    },
    {
      "check_id": "MSG-002",
      "name": "No suspicious tool call patterns",
      "description": "Analyze recent tool calls for dangerous patterns and behavioral anomalies (bash ratio, directory enumeration)",
      "category": "integrity",
      "severity": "critical",
      "type": "python"
    },
    {
      "check_id": "MSG-003",
      "name": "Skills have valid manifests",
      "description": "Verify installed skills have SKILL.md manifests, no dangerous permissions, and no obfuscated code",
      "category": "skills",
      "severity": "high",
      "type": "python"
    },
    {
      "check_id": "MSG-004",
      "name": "Session transcripts accessible and valid",
      "description": "Check session files have proper permissions, valid JSONL, and reasonable sizes",
      "category": "social_guards",
      "severity": "high",
      "type": "python"
    },
    {
      "check_id": "MSG-005",
      "name": "No secrets in conversation context",
      "description": "Scan agent conversation history for leaked credentials, API keys, or tokens",
      "category": "secrets",
      "severity": "critical",
      "type": "python"
    },
    {
      "check_id": "MSG-006",
      "name": "No suspicious URLs in session",
      "description": "Check URLs for data exfiltration services, tunneling, raw IPs, and unusual ports",
      "category": "integrity",
      "severity": "high",
      "type": "python"
    },
    {
      "check_id": "SOC-005",
      "name": "Moltbook posts pass integrity review",
      "description": "If Moltbook skill is installed, find the agent's username and scan recent posts (last 15 min) for moral or integrity violations such as hiding information from humans, discussing credential access, or deceptive behavior",
      "category": "social_guards",
      "severity": "critical",
      "type": "python"
    },
    {
      "check_id": "SOC-006",
      "name": "Human owner has verifiable social reputation",
      "description": "If Moltbook skill is installed, retrieve the human owner's X/Twitter profile and assess reputation based on follower count: <10 followers = no reputation (high risk), 10-1000 = some reputation (medium risk), >1000 = socially verified (low risk)",
      "category": "social_guards",
      "severity": "medium",
      "type": "python"
    }
  ]
}

```

### checks/nodes_media_checks.json

```json
{
  "version": "2.0",
  "description": "OpenClaw Nodes, Media, Gateway, Identity & SubAgent Security Checks (Python-backed)",
  "checks": [
    {
      "check_id": "NODE-001",
      "category": "node_security",
      "name": "Remote execution security setting",
      "description": "Verify remote execution requires approval (ask) or is denied",
      "severity": "critical",
      "type": "python"
    },
    {
      "check_id": "NODE-003",
      "category": "node_security",
      "name": "Node token file permissions",
      "description": "Verify node pairing tokens have restricted permissions",
      "severity": "high",
      "type": "python"
    },
    {
      "check_id": "NODE-005",
      "category": "node_security",
      "name": "Exec allowlist configured",
      "description": "Verify execution allowlist is configured for nodes",
      "severity": "medium",
      "type": "python"
    },
    {
      "check_id": "MEDIA-002",
      "category": "media_security",
      "name": "Media temp directory permissions",
      "description": "Verify media temp directory has restricted permissions",
      "severity": "medium",
      "type": "python"
    },
    {
      "check_id": "MEDIA-003",
      "category": "media_security",
      "name": "Media file type validation",
      "description": "Check if media file type validation is enabled",
      "severity": "medium",
      "type": "python"
    },
    {
      "check_id": "GATEWAY-001",
      "category": "gateway_security",
      "name": "Gateway binding address",
      "description": "Verify gateway is bound to localhost only",
      "severity": "critical",
      "type": "python"
    },
    {
      "check_id": "GATEWAY-002",
      "category": "gateway_security",
      "name": "Gateway authentication enabled",
      "description": "Check if gateway requires authentication",
      "severity": "high",
      "type": "python"
    },
    {
      "check_id": "IDENTITY-001",
      "category": "identity_security",
      "name": "DM pairing allowlist",
      "description": "Check if DM pairing uses allowlist to restrict messaging",
      "severity": "high",
      "type": "python"
    },
    {
      "check_id": "IDENTITY-002",
      "category": "identity_security",
      "name": "Group chat allowlist",
      "description": "Check if group allowlist is configured",
      "severity": "medium",
      "type": "python"
    },
    {
      "check_id": "SUBAGENT-001",
      "category": "subagent_security",
      "name": "SubAgent max concurrent limit",
      "description": "Check if subagent concurrency is limited",
      "severity": "medium",
      "type": "python"
    },
    {
      "check_id": "SUBAGENT-002",
      "category": "subagent_security",
      "name": "SubAgent allowlist configured",
      "description": "Check if subagent target allowlist is set",
      "severity": "medium",
      "type": "python"
    }
  ]
}

```



---

## Skill Companion Files

> Additional files collected from the skill directory layout.

### README.md

```markdown
<p align="center">
  <h1 align="center">πŸ›‘οΈ TrustMyAgent</h1>
  <p align="center"><strong>Security bodyguard for OpenClaw agents</strong></p>
  <p align="center">
    <a href="https://www.trustmyagent.ai">Website</a> &bull;
    <a href="https://www.trustmyagent.ai/trust-center.html">Trust Center</a> &bull;
    <a href="#quick-start">Quick Start</a> &bull;
    <a href="#contributing">Contributing</a>
  </p>
</p>

<p align="center">
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT"></a>
  <a href="https://openclaw.ai"><img src="https://img.shields.io/badge/OpenClaw-skill-green.svg" alt="OpenClaw Skill"></a>
  <img src="https://img.shields.io/badge/checks-41-brightgreen.svg" alt="41 Security Checks">
  <img src="https://img.shields.io/badge/python-3.8+-blue.svg" alt="Python 3.8+">
</p>

---

An EDR-like security agent for [OpenClaw](https://openclaw.ai) agents. Runs 41 security checks across 14 domains, calculates a trust score (0-100), and sends telemetry to a centralized [Trust Center](https://www.trustmyagent.ai/trust-center.html) dashboard where humans and other agents can verify trustworthiness.

**Stateless by design** - runs entirely in memory, stores nothing locally, leaves no traces on the host.

## Why

AI agents are powerful but opaque. When an agent runs on a machine, how do you know it isn't:

- Leaking secrets from environment variables?
- Spawning suspicious processes?
- Accessing files it shouldn't?
- Running with excessive privileges?
- Connecting to exfiltration services?

TrustMyAgent answers these questions every 15 minutes and publishes the results to a public Trust Center so anyone can verify an agent's security posture.

## Quick Start

### As an OpenClaw Skill (recommended)

Copy into your workspace skills directory:

```bash
# From your OpenClaw workspace
mkdir -p skills/trustmyagent
cp -r /path/to/trust-my-agent-ai/* skills/trustmyagent/
```

After installation, ask the agent to run the setup:

> "Set up TrustMyAgent"

The agent will follow the Setup instructions in SKILL.md to install dependencies, run a test assessment, and create the cron job (`*/15 * * * *`) in the `agent:security:main` session stream. See SKILL.md for the full setup steps.

### Standalone

```bash
# Run assessment and send telemetry (agent name from IDENTITY.md)
python3 run.py

```

### Requirements

- Python 3.8+
- `openssl` (for TLS checks)
- No pip dependencies - stdlib only

## Security Domains

| Domain | Checks | Examples |
|--------|--------|---------|
| **Physical Environment** | PHY-001 to PHY-005 | Disk encryption, container isolation, non-root execution |
| **Network** | NET-001 to NET-005 | Dangerous ports, TLS/SSL, DNS resolution, certificates |
| **Secrets** | SEC-001 to SEC-005, MSG-005 | Env var secrets, cloud creds, private keys, conversation leaks |
| **Code** | COD-001 to COD-004 | Git security, no secrets in repos |
| **Logs** | LOG-001 to LOG-004 | System logging active, audit readiness |
| **Skills** | SKL-001 to SKL-005, MSG-001, MSG-003 | Skill manifests, MCP server trust |
| **Integrity** | INT-001 to INT-005, MSG-002, MSG-006 | Backdoors, suspicious tool calls, URL reputation |
| **Social Guards** | SOC-001 to SOC-006, MSG-004 | Action logging, session transparency, Moltbook integrity, owner reputation |
| **Incident Prevention** | INC-001 to INC-005 | Process spawning, system load, port scanning |
| **Node Security** | NODE-001 to NODE-005 | Remote execution approval, token permissions, exec allowlists |
| **Media Security** | MEDIA-002 to MEDIA-003 | Temp directory permissions, file type validation |
| **Gateway Security** | GATEWAY-001 to GATEWAY-002 | Binding address, authentication |
| **Identity Security** | IDENTITY-001 to IDENTITY-002 | DM pairing allowlist, group chat allowlist |
| **SubAgent Security** | SUBAGENT-001 to SUBAGENT-002 | Concurrency limits, target allowlists |

## Trust Scoring

| Tier | Score | Meaning |
|------|-------|---------|
| **HIGH** | 90-100 | Ready for business |
| **MEDIUM** | 70-89 | Needs review |
| **LOW** | 50-69 | Elevated risk |
| **UNTRUSTED** | 0-49 | Critical security gaps |

- Any **critical** failure caps the score at 49 (UNTRUSTED)
- 3+ **high** severity failures cap the score at 69 (LOW)

## Check Types

**Bash checks** (20) - Shell commands that inspect the host environment. Defined in `checks/openclaw_checks.json`.

**Python/Message sensors** (10) - Programmatic checks that analyze secrets, session transcripts, MCP configs, skill manifests, Moltbook posts, and owner reputation. Defined in `checks/message_checks.json`.

**OpenClaw infrastructure checks** (11) - Python checks for node execution, media handling, gateway, identity, and subagent security. Defined in `checks/nodes_media_checks.json`.

All check types auto-detect macOS vs Linux and use platform-appropriate commands.

## Architecture

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      POST /api/telemetry      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Agent Host     β”‚  ─────────────────────────►   β”‚ πŸ›‘οΈ TrustMyAgent Serverβ”‚
β”‚                  β”‚                                β”‚  (Cloudflare)    β”‚
β”‚  run.py          β”‚                                β”‚  β”œβ”€ R2 storage   β”‚
β”‚  β”œβ”€ bash checks  β”‚                                β”‚  β”œβ”€ agents index β”‚
β”‚  └─ python checksβ”‚                                β”‚  └─ trend historyβ”‚
β”‚                  β”‚                                β”‚                  β”‚
β”‚  (no local state)β”‚                                β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                        β”‚
                                                    trust-center.html
                                                    (public dashboard)
```

## Configuration

The agent name is automatically read from your `IDENTITY.md` file (`# Name` section). Falls back to the `OPENCLAW_AGENT_NAME` env var, then `"OpenClaw Agent"`.

| Environment Variable | Description | Default |
|---------------------|-------------|---------|
| `OPENCLAW_AGENT_ID` | Agent identifier | SHA256 of hostname |
| `OPENCLAW_AGENT_NAME` | Override IDENTITY.md name | β€” |
| `TRUSTMYAGENT_TELEMETRY_URL` | Server endpoint | `https://www.trustmyagent.ai/api/telemetry` |

| CLI Flag | Description |
|----------|-------------|
| `--checks`, `-c` | Path to custom checks JSON |
| `--timeout`, `-t` | Per-check timeout in seconds (default: 30) |
| `--quiet`, `-q` | Minimal output |

## Writing Custom Checks

### Bash check

Add to `checks/openclaw_checks.json`:

```json
{
  "check_id": "CUSTOM-001",
  "name": "My custom check",
  "description": "What this check verifies",
  "category": "integrity",
  "severity": "medium",
  "command": "echo 'SAFE'",
  "expected_output": "SAFE",
  "pass_condition": "contains"
}
```

### Python check

Add the definition to `checks/message_checks.json` and the handler to `run.py`:

```python
@python_check("CUSTOM-002")
def check_something(check: dict) -> Tuple[bool, str]:
    # Return (passed: bool, message: str)
    return True, "Everything looks good"
```

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. We welcome:

- New security checks for emerging threat vectors
- Platform support improvements (Windows, ARM)
- Integration with additional agent frameworks
- Trust Center dashboard enhancements

## License

[MIT](LICENSE) - built by [Anecdotes AI](https://anecdotes.ai) for the [OpenClaw](https://openclaw.ai) ecosystem.

```

### _meta.json

```json
{
  "owner": "anecdotes-yair",
  "slug": "trust-my-agent-ai",
  "displayName": "TrustMyAgent",
  "latest": {
    "version": "1.0.0",
    "publishedAt": 1772110632756,
    "commit": "https://github.com/openclaw/skills/commit/2e88c598a215a5b6062c3e65cf7021ca652dd321"
  },
  "history": []
}

```

trustmyagent | SkillHub