live · scanning repos
Scanrepo
github.com
github.com / NousResearch

NousResearch/hermes-agent

Python·10235 files·commit 9cce872·scanned 4d ago·cached ✓
15/100
LOW RISK
Minor findings consistent with the project type. Nothing reachable from install hooks.

score capped at 15235,934+ stars — findings likely false positives

verdict accurate?
235,934 stars
Crypto/Web3 project
24% file coverage
Partial architecture graph
Desktop app detected
threat-state: lowlive

FINDINGS ░▒▓

criticalRust process Command usagestd::process::Command can execute arbitrary shell commands. Malware uses it to drop payloads, exfiltrate data, or establish persistence.apps/bootstrap-installer/src-tauri/src/bootstrap.rs

    let output = std::process::Command::new("git")
        .args(["rev-parse", "HEAD"])
        .current_dir(install_root)
+8
criticalRust process Command usagestd::process::Command can execute arbitrary shell commands. Malware uses it to drop payloads, exfiltrate data, or establish persistence.apps/bootstrap-installer/src-tauri/src/paths.rs
    // executable before the update handoff reaches LaunchServices/Gatekeeper.
    let _ = Command::new("/usr/bin/xattr")
        .args(["-cr"])
        .arg(path)
+8
criticalRust process Command usagestd::process::Command can execute arbitrary shell commands. Malware uses it to drop payloads, exfiltrate data, or establish persistence.apps/bootstrap-installer/src-tauri/src/powershell.rs
    // see `windows_powershell_exe`.
    let mut cmd = Command::new(windows_powershell_exe());
    cmd.arg("-NoProfile");
    cmd.arg("-ExecutionPolicy").arg("Bypass");
+8
warningRust unsafe blockunsafe blocks bypass Rust's memory safety guarantees. Malware uses them for raw pointer manipulation, shellcode injection, or calling dangerous foreign functions.apps/bootstrap-installer/src-tauri/src/update.rs

    unsafe {
        let handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, 0, pid);
        if handle.is_null() {
+3
criticaleval() usage detectedeval() executes arbitrary code and is commonly used in malware to run obfuscated payloads fetched from remote servers.apps/desktop/scripts/perf/lib/cdp.mjs
  /** Evaluate an expression in the page and return its value (awaits promises). */
  async eval(expression) {
    const r = await this.send('Runtime.evaluate', { expression, returnByValue: true, awai...
+8
criticalFunction() constructor detectednew Function() is equivalent to eval() and can execute arbitrary code strings.apps/desktop/src/lib/preview-act/act-in-page.test.ts

    const injected = new Function('return ' + actEngineSource())() as typeof actInPage
    const holder: PreviewActHolder = {}
+5
criticalFunction() constructor detectednew Function() is equivalent to eval() and can execute arbitrary code strings.apps/desktop/src/lib/preview-act/watch-in-page.test.ts

    const injected = new Function('return (' + watchInPage.toString() + ')')() as typeof watchInPage

    expect(() => injected(document, { aimed: target }, 'aim', 'Clicking Save')).not.toThrow()
+5
criticalFunction() constructor detectednew Function() is equivalent to eval() and can execute arbitrary code strings.apps/desktop/src/plugins/hermes-bots/tests/bot-open-focus-identity.test.mjs
  }
  const release = new Function('$openBotChat', `${body}; return releaseStaleOpenBotChat`)($openBotChat)

  // compressed chat: claim carries registry 'reg-1' and tip 'tip-9'
+5
warningPython subprocess / os.system usageos.system() or subprocess with shell=True / suspicious commands can execute arbitrary shell commands. Plain pip/package installs are usually benign.optional-skills/creative/kanban-video-orchestrator/scripts/monitor.py
    try:
        out = subprocess.run(
            ["hermes", "kanban", "list", "--tenant", tenant, "--json"],
            capture_output=True, text=True, encoding='utf-8', errors='replace', check=Fal...
+4
criticalPython dynamic code executioneval(), exec() or compile() on untrusted input can execute arbitrary code. Common in Python malware for running obfuscated payloads.optional-skills/security/godmode/scripts/auto_jailbreak.py
Usage in execute_code:
    exec(open(os.path.expanduser(
        os.path.join(os.environ.get("HERMES_HOME", os.path.expanduser("~/.hermes")), "skills/red-teaming/godmode/scripts/auto_jailbreak.py")
  ...
+7
criticalPython dynamic code executioneval(), exec() or compile() on untrusted input can execute arbitrary code. Common in Python malware for running obfuscated payloads.optional-skills/security/godmode/scripts/godmode_race.py
Usage in execute_code:
    exec(open(os.path.join(os.environ.get("HERMES_HOME", os.path.expanduser("~/.hermes")), "skills/red-teaming/godmode/scripts/godmode_race.py")).read())
    
    result = race_...
+7
criticalPython dynamic code executioneval(), exec() or compile() on untrusted input can execute arbitrary code. Common in Python malware for running obfuscated payloads.optional-skills/security/godmode/scripts/load_godmode.py
Usage in execute_code:
    exec(open(os.path.expanduser(
        os.path.join(os.environ.get("HERMES_HOME", os.path.expanduser("~/.hermes")), "skills/red-teaming/godmode/scripts/load_godmode.py")
    ...
+7
warningPython subprocess / os.system usageos.system() or subprocess with shell=True / suspicious commands can execute arbitrary shell commands. Plain pip/package installs are usually benign.scripts/check-windows-footguns.py
            "else:\n"
            "    subprocess.run(['powershell', '-NoProfile', '-Command',\n"
            "                    'Get-CimInstance Win32_Process | ...'])"
        ),
+4
warningPython subprocess / os.system usageos.system() or subprocess with shell=True / suspicious commands can execute arbitrary shell commands. Plain pip/package installs are usually benign.scripts/ci/lockfile_diff.py
    """Contents of ``path`` at ``ref``, or None if it doesn't exist there."""
    proc = subprocess.run(
        ["git", "show", f"{ref}:{path}"],
        capture_output=True,
+4
criticalRemote script piped into a shellA shell script downloads remote content and executes it directly (e.g. `curl … | bash`). The payload is never stored or reviewable and can change server-side — a classic malware/backdoor install pattern.scripts/dev-sandbox.sh
    set +e
    curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash -s -- "$@"
    install_status=$?
    if [ "$install_status" -eq 0 ] && [ -f /work/promote-main ]; then
+10
criticalchild_process / exec usageExecuting shell commands can be used to download and run malware, exfiltrate data, or modify system files.apps/desktop/electron/bootstrap-runner.ts
    ((args, cwd) =>
      execFileSync('git', args, {
        cwd,
        encoding: 'utf8',
+8
criticalchild_process / exec usageExecuting shell commands can be used to download and run malware, exfiltrate data, or modify system files.apps/desktop/electron/update-handoff-marker.test.ts

  return spawnSync('/bin/bash', [POSIX_SCRIPT, '--daemonized', '--install-root', installRoot, '--self-test-marker'], {
    env,
    encoding: 'utf8'
+8
infoSuspicious files are not reachable from entry pointsFlagged files exist but are not imported by any entry point. They may be dead code, tests, or attack payloads triggered by another mechanism.+2
warningHardcoded IP address in network callFetching data from hardcoded IP addresses instead of domain names is suspicious and may indicate C2 communication.apps/desktop/src/components/boot-failure-overlay.test.tsx
  remoteTokenSet: true,
  remoteUrl: 'http://100.116.104.53:9191',
  cloudOrg: ''
}
+5
warningHardcoded IP address in network callFetching data from hardcoded IP addresses instead of domain names is suspicious and may indicate C2 communication.apps/desktop/src/lib/remote-url.test.ts
  it('prepends http:// to scheme-less host:port input', () => {
    expect(coerceRemoteUrlScheme('100.64.0.1:9119')).toBe('http://100.64.0.1:9119')
    expect(coerceRemoteUrlScheme('mini.tailnet-1234....
+5
warningHardcoded IP address in network callFetching data from hardcoded IP addresses instead of domain names is suspicious and may indicate C2 communication.agent/model_metadata.py
# block, so without an explicit check Ollama reached over Tailscale (e.g.
# `http://100.77.243.5:11434`) wouldn't be treated as local and its stream
# read / stale timeouts wouldn't get auto-bumped. B...
+5
warningSSH/credential path accessAccessing .ssh, .aws/credentials, or .env files to steal authentication credentials.apps/desktop/src/app/settings/ssh-host-selection.test.ts
      enrichSelectedSshHost(selected, 'mac-box', {
        identityFile: '~/.ssh/id_ed25519',
        port: 22,
        user: 'hermes'
+5
criticalBrowser credential store accessAccessing Chrome, Firefox, Edge, or Brave profile directories to steal cookies, passwords, and session tokens.optional-skills/security/unbroker/scripts/cdp.py
        r"Chromium\Application\chrome.exe",
        r"BraveSoftware\Brave-Browser\Application\brave.exe",
        r"Microsoft\Edge\Application\msedge.exe",
    ]
+10
warningSSH/credential path accessAccessing .ssh, .aws/credentials, or .env files to steal authentication credentials.acp_adapter/edit_approval.py

SENSITIVE_AUTO_APPROVE_NAMES = {".env", ".env.local", ".env.production", "id_rsa", "id_ed25519"}
AUTO_APPROVE_ASK = "ask"
AUTO_APPROVE_WORKSPACE = "workspace_session"
+5
warningSSH/credential path accessAccessing .ssh, .aws/credentials, or .env files to steal authentication credentials.agent/context_references.py
_NEEDS_QUOTING = re.compile(r"""[\s()\[\]{}<>"'`]""")
_SENSITIVE_HOME_DIRS = (".ssh", ".aws", ".gnupg", ".kube", ".docker", ".azure", ".config/gh")
_SENSITIVE_HERMES_DIRS = (Path("skills") / ".hub",)
...
+5
warningExtremely long lines (>1000 chars)Very long lines in source files (not minified bundles) can hide malicious code.apps/desktop/src/components/ui/tool-icon.tsx+4
warningFlattened or dead control flowDetected switch(true), dead if branches, or deeply nested ternaries — patterns used by obfuscators to hide execution order.apps/desktop/src/app/session/hooks/use-message-stream/index.ts+3
warningFlattened or dead control flowDetected switch(true), dead if branches, or deeply nested ternaries — patterns used by obfuscators to hide execution order.apps/desktop/src/app/session/hooks/use-prompt-actions/index.ts+3
warningFlattened or dead control flowDetected switch(true), dead if branches, or deeply nested ternaries — patterns used by obfuscators to hide execution order.apps/desktop/src/app/session/hooks/use-session-actions/index.ts+3
warningHigh-entropy string literalsFound 4 long strings with high Shannon entropy. This is common in obfuscated payloads that hide URLs, keys, or bytecode.apps/bootstrap-installer/src/components/button.tsx+3
warningHigh-entropy string literalsFound 3 long strings with high Shannon entropy. This is common in obfuscated payloads that hide URLs, keys, or bytecode.apps/desktop/scripts/before-pack.mjs+3
warningHigh-entropy string literalsFound 3 long strings with high Shannon entropy. This is common in obfuscated payloads that hide URLs, keys, or bytecode.apps/desktop/scripts/diag-drag-churn.mjs+3
warningLarge base64-encoded blobA 92-character base64 blob was found. May hide a remote payload or encoded executable code.apps/desktop/src/lib/image-resize.test.ts
iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8...
+3
warningLarge base64-encoded blobA 376-character base64 blob was found. May hide a remote payload or encoded executable code.apps/desktop/e2e/image-attachment-resume.spec.ts
iVBORw0KGgoAAAANSUhEUgAAAKAAAABkCAIAAACO1KzYAAAA30lEQVR42u3d...
+3
infoSuspicious file in repoVery large source file (554KB) — could contain obfuscated payloadapps/desktop/electron/main.ts+2
infoSuspicious file in repoVery large source file (580KB) — could contain obfuscated payloadapps/desktop/src/plugins/hermes-bots/plugin.js+2
infoSuspicious file in repoVery large source file (986KB) — could contain obfuscated payloadcli.py+2
infoAuthor has no other public repositoriesGitHub user "hermes-seaeye[bot]" has no other public repositories, common for burner accounts used in scams.+2

Scores are heuristics. A “safe” verdict means no known-malicious patterns were found — clever malware can look boring. Wrong verdict? Flag it above; confirmed false positives become regression tests.

2476 files scanned @ 9cce872 | 8/25/2026 | heuristic scan — always review manually

risk by category
code execution25
network & exfiltration25
file system access20
obfuscation15
supply chain15
owasp / injection0
telemetry
files 2476/10235rules hit 38engine v5commit 9cce872

github

NousResearch/hermes-agent

The agent that grows with you

Python
235934
47602
403d
10235 files
2476 scanned(24%)
9cce872

architecture░▒▓

entry (2) flagged (528) pkg (876)
1406 nodes · 4269 edgesscroll to zoom · click node to jump to finding