superghidra
HIGH
maintainer lapsus
0 votes
scanned 2026-11-01 18:01:05.785766
Why flagged
curl/wget/fetch output reaches a shell (via pipe, xargs, process substitution, `sh -c "$(…)"`, or `| source`), executing remote code that was never reviewed or checksummed.
Triggered rules
High
Remote download executed by a shell
curl_pipe_shell
curl/wget/fetch output reaches a shell (via pipe, xargs, process substitution, `sh -c "$(…)"`, or `| source`), executing remote code that was never reviewed or checksummed.
-
PKGBUILD:27
curl -fsSL "https://pypi.org/pypi/${pkgname}/json" |
Low
Few votes, recently uploaded
zero_votes_recent
Uploaded within the last 14 days with 2 or fewer community votes — little peer review so far.
PKGBUILD
1 offending line(s) highlighted
1
# Maintainer: Yakov Till <yakov.till@gmail.com>
2
3
pkgname=superghidra
4
pkgver=1.0.7
5
pkgrel=1
6
pkgdesc='Reverse-engineering suite for Ghidra: P-code lifting, Z3, binary diffing'
7
arch=('any')
8
url="https://github.com/yuatemycat/SuperGhidra"
9
license=('AGPL-3.0-or-later')
10
depends=('python' 'python-numpy')
11
makedepends=('python-build' 'python-installer' 'python-setuptools')
12
# The Ghidra-bridge and GPU extras are not listed: upstream imports `pyghidra`
13
# and `wgpu` lazily, and no package in the repos or the AUR provides either
14
# module, so naming them would add dependencies pacman cannot resolve. Users who
15
# want those two backends install them from PyPI rather than through pacman.
16
optdepends=(
17
'python-z3-solver: prove two P-code snippets equivalent, or answer UNKNOWN'
18
'python-lz4: LZ4 compression of Ghidra 16 KB buffer pages'
19
'python-zstandard: Zstandard compression of Ghidra 16 KB buffer pages'
20
'python-frida: inspect a live emulator at runtime'
21
'python-psutil: apply the CPU affinity and priority of each resource mode, and validate an emulator process by executable name'
22
)
23
source=("${pkgname}-${pkgver}.tar.gz::https://files.pythonhosted.org/packages/source/${pkgname::1}/${pkgname}/${pkgname}-${pkgver}.tar.gz")
24
sha256sums=('9e10bee07b3d17e028349e82f828fda1a2b559e570c8906c5d62749e277eaa24')
25
26
latestver() {
27
curl -fsSL "https://pypi.org/pypi/${pkgname}/json" |
28
python -c 'import json, sys; print(json.load(sys.stdin)["info"]["version"])'
29
}
30
31
build() {
32
cd "$srcdir/${pkgname}-${pkgver}"
33
python -m build --wheel --no-isolation
34
}
35
36
# The sdist ships no upstream test suite, so this asserts the published surface
37
# instead. The wheel installs the package plus ~30 top-level modules that
38
# sibling projects import by their bare names, and every optional backend is
39
# imported lazily, so importing the whole surface is what proves a default
40
# install needs no optional dependency and that nothing was dropped or shadowed
41
# in packaging. That surface is only importable once installed, so the wheel is
42
# installed into a throwaway root first; the same install is what proves the
43
# JSON schemas reached site-packages, since they are opened by path rather than
44
# through the import system. `filter` is asserted because it is the subcommand
45
# that exercises the lifting stack without invoking Ghidra, and its output is
46
# checked rather than its exit status.
47
check() {
48
cd "$srcdir/${pkgname}-${pkgver}"
49
python - <<'PY'
50
import importlib
51
import os
52
import pathlib
53
import subprocess
54
import sys
55
import tempfile
56
import zipfile
57
58
wheel = next(pathlib.Path("dist").glob("*.whl"))
59
with zipfile.ZipFile(wheel) as archive:
60
shipped = [name for name in archive.namelist() if name.endswith(".py")]
61
62
63
def dotted(name):
64
parts = name.removesuffix(".py").split("/")
65
if parts[-1] == "__init__":
66
parts.pop()
67
return ".".join(parts)
68
69
70
modules = sorted(module for module in map(dotted, shipped) if module)
71
72
with tempfile.TemporaryDirectory() as tmp:
73
install = subprocess.run(
74
[sys.executable, "-m", "installer", f"--destdir={tmp}", str(wheel)],
75
capture_output=True,
76
text=True,
77
)
78
assert install.returncode == 0, install.stderr
79
80
installed = pathlib.Path(tmp)
81
site = next(installed.glob("usr/lib/python3.*/site-packages"))
82
sys.path.insert(0, str(site))
83
84
for module in modules:
85
importlib.import_module(module)
86
print(f"imported {len(modules)} modules")
87
88
validator = importlib.import_module("superghidra.schemas.validator")
89
for schema in validator.SCHEMA_FILES:
90
validator.load_schema(schema)
91
print(f"loaded {len(validator.SCHEMA_FILES)} schemas")
92
93
raw = "undefined4 main(void)\n{\n return 0;\n}\n"
94
with tempfile.TemporaryDirectory() as work:
95
source = pathlib.Path(work) / "raw.c"
96
source.write_text(raw)
97
done = subprocess.run(
98
[str(next(installed.glob("usr/bin/superghidra"))), "filter", str(source)],
99
capture_output=True,
100
text=True,
101
env={**os.environ, "PYTHONPATH": str(site)},
102
)
103
104
assert done.returncode == 0, done.stderr
105
assert "uint32_t main(void)" in done.stdout, done.stdout
106
assert "#include <stdint.h>" in done.stdout, done.stdout
107
print("cli filter: rewrote undefined4 to uint32_t with headers")
108
PY
109
}
110
111
package() {
112
cd "$srcdir/${pkgname}-${pkgver}"
113
python -m installer --destdir="$pkgdir" dist/*.whl
114
}
115
Changes since previous scan
--- PKGBUILD @ 2026-10-29 15:57+++ PKGBUILD @ 2026-11-01 18:01@@ -1,7 +1,7 @@ # Maintainer: Yakov Till <yakov.till@gmail.com> pkgname=superghidra-pkgver=1.0.4+pkgver=1.0.7 pkgrel=1 pkgdesc='Reverse-engineering suite for Ghidra: P-code lifting, Z3, binary diffing' arch=('any')@@ -21,7 +21,7 @@ 'python-psutil: apply the CPU affinity and priority of each resource mode, and validate an emulator process by executable name' ) source=("${pkgname}-${pkgver}.tar.gz::https://files.pythonhosted.org/packages/source/${pkgname::1}/${pkgname}/${pkgname}-${pkgver}.tar.gz")-sha256sums=('e23bb0b41a509de32b8ed3ca55e179b6e6e327317998e8e218a9704baad37e52')+sha256sums=('9e10bee07b3d17e028349e82f828fda1a2b559e570c8906c5d62749e277eaa24') latestver() { curl -fsSL "https://pypi.org/pypi/${pkgname}/json" |Scan history
| Scanned at (UTC) | Severity | Rules |
|---|---|---|
| 2026-11-01 18:01:05 | High | 2 |
| 2026-10-31 16:00:52 | Clean | 3 |
| 2026-10-31 15:58:34 | High | 2 |
| 2026-10-29 15:57:14 | Clean | 3 |
| 2026-10-29 15:52:51 | High | 2 |
| 2026-10-28 01:50:59 | Clean | 3 |
| 2026-10-28 01:49:03 | High | 2 |
| 2026-10-26 13:48:09 | Clean | 3 |
| 2026-10-26 13:45:05 | High | 2 |
| 2026-10-24 03:40:57 | Clean | 3 |
| 2026-10-24 03:39:05 | High | 2 |