Yashcshah/pkgids

GitHub: Yashcshah/pkgids

一款通过在 gVisor 隔离沙箱内动态引爆开源包并分析网络行为来检测供应链恶意软件的工具。

Stars: 1 | Forks: 0

# pkgids:行为包引爆环境 pkgids 是一款用于开源包的动态恶意软件检测工具。它从 PyPI 或 npm 下载软件包,在一个连接到模拟互联网的 gVisor 隔离沙箱内将其引爆。该模拟互联网会捕获所有网络行为,同时阻止真实的外部流量,并标记出在安装或导入过程中试图进行秘密通信或表现出恶意行为的包。与静态源代码分析工具相比,其核心优势在于基于行为和网络层面的检测。pkgids 能够捕获那些通过逃避基于 grep 或 AST 扫描的混淆 payload,其方式是在受控环境中实际执行它们并监视其行为。 ## 为什么开发此工具 通过恶意包发起的开源供应链攻击是一个日益增长且未被充分重视的威胁向量。攻击者会发布名称与流行库相似的包(typosquatting,域名抢注/拼写错误),注入合法包的恶意版本,或者通过社会工程学诱骗维护者合并后门。这些 payload 通常在安装时(setup.py、package.json 脚本)或首次导入时执行,而此时大多数用户还没有任何理由产生怀疑。 静态工具可以捕获明显的危险信号,例如使用 subprocess、os.system 或已知的恶意 URL。但真实的恶意软件通常会通过 base64 编码、多阶段 payload 和动态 URL 构造来逃避检测。行为分析则通过运行包并观察其实际尝试的网络连接来绕过所有这些手段。 在开发过程中的一项发现:我查询了 OpenSSF malicious-packages 数据集中 100 个已记录的恶意 PyPI 包,在执行查询时,每一个包都已经被从注册表中移除。注册表的移除时间是非零的。实时的、安装前的行为检测器是保护在注册表做出反应之前就遇到该包的用户的唯一方法。 ## 验证结果 pkgids 已通过包含 7 个样本的自行构建的已标注语料库(6 种不同的恶意技术加上 1 个良性对照组)进行了验证,每个样本都被构建为本地 PyPI sdist 并通过完整流水线进行引爆。 | 样本 | 技术 | 预期 | 结果 | |---|---|---|---| | canary-http-install | 在 setup.py 中执行 urllib GET | malicious | TP | | canary-dns-exfil | base32 编码的子域名 DNS 查询 | malicious | TP | | canary-env-harvest | 读取环境变量 + ~/.ssh/id_rsa 长度后进行 GET | malicious | TP | | canary-subprocess | 启动 python3 -c "urlopen(...)" | malicious | TP | | canary-base64-blob | 执行 exec(base64.b64decode(_BLOB)) 并发起 GET | malicious | TP | | canary-import-callback | 仅在 \_\_init\_\_.py 中的回调 | malicious | FN | | benign-clean-control | 什么都不做 | benign | TN | **检出率:83.3% (5/6)。误报率:0%。** 其中唯一的一例漏报(canary-import-callback)是“局限性”部分中描述的已知架构限制。值得注意的是,那种能够击败源代码扫描器的 base64 混淆 payload 被成功检测到了。这正是行为分析的核心意义所在。 ## 架构 请参阅 [architecture.md](architecture.md) 获取完整的系统图表。 ``` fetch.py dataset.py validate.py (download only) (OpenSSF metadata) (labeled corpus run) | v +----------------------------------------------------------+ | Contained detonation (capture.py + sandbox.py) | | gVisor runsc internal network no real egress | | | | +---------------------+ phones home +----------+ | | | Sandbox container | ----------------> | Fake-inet| | | | install -> import | | appliance| | | | non-root (deton) | | DNS + TCP| | | | resolv.conf->appl. | | JSONL log| | | +---------------------+ +----------+ | | +---------------------+ +--------------------------+ | | | tcpdump on bridge | | Per-phase attribution | | | | capture.pcap | | timestamp-window filter | | | +---------------------+ +--------------------------+ | +----------------------------------------------------------+ | v +----------------------------------------------------------+ | Verdict (run.json) | | network_activity -> malicious / benign | | 83.3% detection 0% false-positive rate | +----------------------------------------------------------+ ``` ### 流水线阶段 1. **获取** - fetch.py 从 PyPI 或 npm 下载包构件,验证 SHA-256 或 SRI 完整性摘要,并写入 metadata.json(上传时间、维护者、文件列表、安装钩子是否存在)。宿主机上不会执行任何内容。 2. **tcpdump** - capture.py 确定 detonet 的 Linux 网桥接口,并在其上启动 tcpdump -w capture.pcap。在宿主机上运行,尽最大努力捕获。 3. **安装阶段** - sandbox.py 调用 docker run --runtime runsc,并配置 --network detonet、资源限制以及指向该设备的自定义 resolv.conf。沙箱会为 PyPI 运行 pip3 install --break-system-packages --no-build-isolation --no-deps /work/,或为 npm 运行 npm install。Stdout、stderr、退出码和持续时间会被记录到 install.json 中。 4. **导入阶段** - 同一个容器运行 python3 -c "import sys; sys.path.insert(0, '/scratch/site-packages'); import ",以便可以使用在第 3 步中安装的包。结果记录到 import.json 中。 5. **停止 tcpdump** - 刷新 pcap 文件。 6. **分阶段归因** - 每次沙箱调用都通过 time.time() 快照划定边界,形成一个 [t_start, t_end] 时间窗口。_read_phase_entries() 读取设备的 JSONL 日志,并仅保留 ts 字段落在该窗口内的条目。来自 IP 回收的过期条目将被排除。这是针对一个误报漏洞的修复方案,在该漏洞中,由于 Docker 回收了前一次运行的 detonet IP,导致前一次运行的流量被归因于一个良性包。 7. **公告情报富化** - fetch.py 向 OSV.dev 查询影响该包名称和版本的已知公告。标准化后的结果(命中、数量、ID、摘要、错误)与构件一起存储在 metadata.json 中,并呈现在报告中。如果 OSV 查询失败或超时,运行将继续;advisory_error 会记录原因。 8. **判定** - 每份报告中都会出现三个明确区分的判定字段: - `behavioral_verdict` — 仅包含运行时证据,来自累加评分模型:`no_malicious_behavior_observed`(分数=0)/ `low_risk`(1–24)/ `suspicious`(25–49)/ `likely_malicious`(50–74)/ `malicious`(75–100)。**没有动态信号并不意味着安全。** - `advisory_status` — 仅表示公告状态:`none`(OSV 未发现任何内容)/ `advisory_hit`(一个或多个公告匹配此版本)/ `lookup_failed`(查询超时或出错)。 - `final_verdict` / `verdict` — 面向分析师的综合判定。公告命中会将没有或仅有较低动态信号的包提升为 `known_vulnerable`;`suspicious` 或更高的动态信号将被保留,且 `verdict_basis` 会被设置为 `"both"`。 ## 安全与隔离 | 层级 | 机制 | 目的 | |---|---|---| | 内核隔离 | gVisor --runtime runsc | 在 syscall 到达宿主机内核之前进行拦截;受到入侵的包无法利用内核 CVE | | 网络隔离 | --network detonet(内部网桥) | Docker iptables 规则丢弃所有转发的数据包;无法访问真实的互联网 | | DNS 欺骗 | bind-mount resolv.conf 指向设备 | 在 gVisor 下,Docker 内置的解析器 (127.0.0.11) 不起作用;挂载自定义文件会将所有 DNS 路由到该设备 | | 模拟互联网 | pkgids-fakeinternet 设备 | 接受连接并记录它们,而不是进行转发;让包认为它已连接到互联网 | | 非 root 执行 | 容器内的 --user deton | 限制容器逃逸攻击造成的损害 | | 内存限制 | --memory 1g | 防止宿主机遭受 OOM 攻击 | | CPU 限制 | --cpus 1.0 | 防止 CPU 耗尽 | | PID 限制 | --pids-limit 256 | 防止 fork 炸弹 | | 挂钟超时 | 默认 120 秒 (sandbox.timeout_secs) | 超时后进程将被杀死;结果中会记录 timed_out=true | | 临时容器 | 在 finally 代码块中执行 docker rm -f | 即使在超时或发生异常时也会移除容器;不保留任何状态 | | 只读工作目录 | --mount type=bind,...,readonly | 构件在容器内可见,但无法被修改 | | 可写临时区 | --mount type=tmpfs,target=/scratch | 内存中的临时空间,在容器退出时即消失 | ## 组件 | 文件 | 职责 | |---|---| | pkgids/fetch.py | 下载 PyPI(优先使用 sdist,回退使用 wheel)和 npm(tarball)构件。验证 SHA-256 (PyPI) 或 SRI sha512- 哈希 (npm)。写入包含上传时间戳、维护者、归档成员列表和安装钩子检测的 metadata.json。绝不执行任何内容。 | | pkgids/sandbox.py | 封装 docker run --runtime runsc。管理 resolv.conf 临时文件(gVisor DNS 修复)、每次运行唯一的容器名称、启动后的 IP 轮询(以便在容器退出且 Docker 清除 NetworkSettings 之前获取 detonet IP)、资源限制以及通过 finally 保证的清理操作。 | | pkgids/capture.py | 流水线编排器。获取或使用本地构件,启动 tcpdump,运行安装和导入阶段,收集基于时间窗口的设备日志,并写入 install.json、import.json、network.jsonl 和 run.json。 | | pkgids/validate.py | 读取已标注的 CSV,为每个样本运行 capture.run()(跳过已完成的行以便恢复),计算 TP/FP/TN/FN 以及检出率和误报率。支持 --local-artifacts 以从本地 sdists 进行语料库验证。 | | pkgids/dataset.py | 通过 GitHub Contents API 从 OpenSSF malicious-packages 仓库获取恶意包记录。返回 ecosystem、name、version、osv_id、summary 字典。结果缓存到 data/malicious_.json。 | | pkgids/analyze.py | 跨流关联引擎。通过结合 strace 遥测数据和网络日志,检测“文件读取先于数据窃取”、“shell 调用先于网络活动”以及“subprocess payload”模式。将 correlations.json 写入运行目录。 | | pkgids/advisory.py | 尽力而为的 OSV.dev 公告查询。返回标准化的 6 字段摘要(advisory_hit、advisory_source、advisory_count、advisory_ids、advisory_summaries、advisory_error)。绝不抛出异常;错误会被记录在 advisory_error 中。 | | pkgids/score.py | 累加式 0–100 评分模型。包含 16 个加权指标;当凭据访问和 HTTP/TLS 同时出现时,给予 +25 的数据窃取组合加成。五级行为判定:no_malicious_behavior_observed / low_risk / suspicious / likely_malicious / malicious。 | | pkgids/report.py | 包含六个问题的 HTML + JSON 报告:发生了什么、为何做出此判定、哪个阶段、哪个主机、哪个文件,以及它与基线有何不同。区分动态行为判定、公告情报和最终面向分析师的判定。将 behavior_profile.json 和 diff.json 连同报告一起写入运行目录。 | | infra/fakeinternet/responder.py | 纯标准库 Python。DNS 服务器(UDP 53),将每个主机名解析为其自身。在端口 21、25、80、443、8080 上监听 TCP。提取 HTTP Host 标头和请求行、TLS SNI、SMTP/FTP 横幅。将 JSONL 写入 /logs/.jsonl。 | ## 使用方法 ### 前置条件 - 安装了 Docker 和 gVisor 的 Linux(runsc 运行时已向 Docker 注册) - Python 3.11+ ### 安装 ``` git clone https://github.com/Yashcshah/pkgids.git cd pkgids python -m venv .venv && source .venv/bin/activate pip install -e . ``` ### 构建沙箱镜像 ``` make sandbox-image ``` ### 启动模拟互联网设备 ``` make detonet make fakeinternet-start ``` ### 核心命令 下载包而不运行任何内容: ``` pkgids fetch pypi requests 2.31.0 pkgids fetch npm lodash 4.17.21 ``` 通过完整流水线引爆包: ``` pkgids detonate pypi requests 2.31.0 pkgids detonate npm lodash 4.17.21 --skip-import pkgids detonate pypi six 1.16.0 --run-dir /tmp/six-run ``` 默认情况下,pip 会使用 `--no-deps` 运行,从而将包隔离。若要允许在同一个受沙箱保护的模拟互联网环境中安装依赖(适用于恶意行为由依赖代码触发的包): ``` pkgids detonate pypi some-package 1.0 --with-deps ``` 依赖项会通过模拟互联网汇聚点进行获取。网络出站流量仍然被阻止;如果无法访问 PyPI,依赖项获取将会失败,从而导致 `install_status=failed`。此模式最适用于您怀疑存在由依赖项引发的恶意行为,并且愿意接受较多噪音运行的情况。默认的 `--no-deps` 行为保持不变。 输出将被写入 `runs/---/` 目录下的 `run.json` 中。 浏览 OpenSSF malicious-packages 数据集而不执行任何操作: ``` pkgids dataset fetch pypi --limit 20 pkgids dataset fetch npm --limit 50 --token $GITHUB_TOKEN ``` 针对带标签的 CSV 进行验证: ``` # 针对 live registry packages: pkgids validate --samples data/benign_samples.csv # 针对本地构建的 corpus sdists(corpus/ 必须单独构建,见 Corpus 部分): pkgids validate --samples data/corpus_samples.csv --local-artifacts ``` 验证支持断点续传。data/validation_results.json 中已存在的样本在重新运行时会被跳过。 ### 批量扫描(requirements / SBOM / CSV) 通过完整的引爆 + 报告流水线扫描 `requirements.txt`、CycloneDX JSON SBOM 或普通 CSV 文件中的每一个包: ``` # 扫描 pinned requirements 文件 pkgids scan requirements.txt # 扫描由 dependency scanner 生成的 CycloneDX SBOM pkgids scan sbom.json # 扫描纯 CSV(列:ecosystem, name, version) pkgids scan packages.csv --output-dir results/ # 跳过 per-package export bundles 以便快速执行 pkgids scan requirements.txt --no-export # 即使存在之前的 batch_results.json 也重新运行所有内容 pkgids scan requirements.txt --no-resume ``` 输入格式规则: | 格式 | 识别方式 | 版本要求 | |---|---|---| | `requirements.txt` | 文件名或 `*require*.txt` |限 `==` 固定版本 — `>=` 会发出警告并跳过 | | CycloneDX JSON | 包含 `"bomFormat"` + `"CycloneDX"` 的 `.json` 文件 | PURL `@version` 或组件 `version` 字段中的版本;若缺失 → 跳过 | | 普通 CSV | `.csv` 扩展名 | `version` 列必须非空 | v1 支持的生态系统:`pypi`、`npm`。属于其他生态系统的行将被跳过,并向 stderr 打印警告。 输出位于 `scan-/`(或 `--output-dir`): ``` scan-20240621T120000Z/ batch_results.json # structured summary + per-package verdicts; resumable batch_report.html # single-table HTML report with verdict colouring ``` 退出代码遵循与 `pkgids detonate` 相同的策略: | 代码 | 含义 | |---|---| | `0` | 所有包均无异常(或没有包) | | `1` | 至少有一个 `suspicious` 或 `known_vulnerable` | | `2` | 至少有一个 `malicious` 或 `likely_malicious` | 批量扫描是**可恢复的**:使用相同的 `--output-dir` 重新运行相同的命令,将跳过已存在于 `batch_results.json` 中的包。传入 `--no-resume` 可强制进行完全重新扫描。 `requirements.txt` 的附加项会被剔除(`requests[security]==2.28.0` → 仅扫描 `requests`)。重复条目(相同的 ecosystem:name:version)会被去重 — 以第一次出现的为准。 ### 演示:确认模拟互联网捕获有效 ``` make demo-fake ``` 运行 DNS 和 HTTP 金丝雀测试,打印捕获日志,并确认没有发生真实的出站流量。 ## 输出文件 每次 pkgids 引爆运行都会在 runs/ 下创建一个目录: ``` runs/20240621T120000Z-pypi-six-1.16.0/ install.json # command, stdout, stderr, exit_code, duration, window [t0,t1] import.json # same for import phase network.jsonl # timestamp-filtered fakeinternet entries for this run only capture.pcap # tcpdump on detonet bridge (requires host root; skipped if unavailable) run.json # summary: phases, network_activity per phase, paths to all outputs ``` network.jsonl 条目如下所示: ``` {"ts": 1719000001.23, "type": "dns", "src": "10.200.200.3", "query": "evil.example.com", "resolved_to": "10.200.200.2"} {"ts": 1719000001.31, "type": "tcp", "src": "10.200.200.3", "dst_port": 80, "protocol": "http", "host": "evil.example.com", "request_line": "GET /steal?data=secret HTTP/1.1"} ``` ## 配置 所有配置项都位于 config.toml 中: ``` [sandbox] image = "pkgids-sandbox:latest" runtime = "runsc" # set to "runc" to disable on machines without gVisor timeout_secs = 120 memory = "1g" cpus = 1.0 pids_limit = 256 [fakeinternet] network = "detonet" subnet = "10.200.200.0/24" container_name = "pkgids-fakeinternet" ip = "10.200.200.2" logs_dir = "logs/fakeinternet" [detonation] runs_dir = "runs" skip_import = false clear_logs_each_run = true ``` ## Supabase 设置(仅用于可选的远程持久化) pkgids 在不使用 Supabase 的情况下会在本地生成所有运行构件。每次引爆都会将 `run.json`、`network.jsonl`、`telemetry.jsonl`、`behavior_profile.json`、`correlations.json` 以及(当提供 diff 时)`diff.json` 写入运行目录。这些都不需要数据库。 仅在执行以下远程持久化命令时才需要 Supabase: | 命令 | 功能描述 | |---|---| | `pkgids baseline push` | 将行为配置文件存储到云端 | | `pkgids baseline list / show` | 查询已存储的配置文件 | | `pkgids diff --push` | 持久化保存差异结果 | | `pkgids report`(自动对比) | 获取已存储的配置文件以计算差异;如果不可用则跳过并发出警告 | ### Schema 完整的 Schema 存在于两个文件中,必须按顺序运行: ``` migrations/001_baseline_schema.sql ~ packages, behavior_profiles, behavior_diffs tables migrations/002_add_risk_delta.sql ~ adds risk_delta column to behavior_diffs ``` 应用方法:打开您项目的 Supabase 仪表板 → SQL Editor → New Query → 粘贴并按顺序运行每个文件。 这会创建三个表: | 表 | 用途 | 关键约束 | |---|---|---| | `packages` | 每个 (ecosystem, name, version) 对应一行 | `UNIQUE (ecosystem, name, version)` | | `behavior_profiles` | 每次引爆运行对应一行 | FK → `packages.id` | | `behavior_diffs` | 每个比较的版本对对应一行 | `UNIQUE (ecosystem, name, from_version, to_version)`;FK → `behavior_profiles.id` (可为空) | 这三个表都启用了行级安全策略,且具有开放策略(`FOR ALL TO anon, authenticated`)。在公开暴露项目之前,请收紧这些权限。 ### 环境变量 ``` # 任何 remote persistence command 所必需。 # 添加到项目根目录的 .env 文件中(自动加载)。 SUPABASE_URL=https://.supabase.co SUPABASE_KEY= ``` 或者,如果您与前端应用共享同一个 Supabase 项目: ``` NEXT_PUBLIC_SUPABASE_URL=https://.supabase.co NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY= ``` 当同时设置两者时,`SUPABASE_URL`/`SUPABASE_KEY` 的优先级高于 `NEXT_PUBLIC_` 变体。 ### 未配置 Supabase 时的行为 任何远程持久化命令退出时都会提示: ``` error: Supabase credentials missing. Set SUPABASE_URL + SUPABASE_KEY in .env or as environment variables. Schema: run migrations/001_baseline_schema.sql then migrations/002_add_risk_delta.sql in the Supabase SQL editor. See the 'Supabase Setup' section in README.md for full instructions. ``` `pkgids detonate` 和 `pkgids report` 不受影响,它们只会写入本地构件。 ## 语料库 corpus/ 包含七个自行编写的示例包。每一个都是可构建的 PyPI sdist,演示了一种恶意软件技术。所有目标都指向 canary-test.example.com,这是一个在真实互联网上无法访问的虚假汇聚点。 `corpus/` 目录和 `build_all.sh` 脚本不包含在仓库中。要构建语料库 sdist,请根据 `data/corpus_samples.csv` 中的描述重建每个包目录,然后在每个目录中运行 `python setup.py sdist`,并更新 `artifact_path` 列使其指向生成的 `.tar.gz` 文件。`data/corpus_samples.csv` 文件列出了 `/root/pkgids/corpus/dist/` 下的预期构件路径。 一旦 sdist 可用,运行以下命令进行验证: ``` pkgids validate --local-artifacts data/corpus_samples.csv ``` ## 判定参考 每份报告都包含三个明确区分的判定字段: ### 行为判定 (`behavioral_verdict`) 完全来源于通过 `score.py` 中的累加评分模型得出的沙箱运行时证据。 | 值 | 分数 | 含义 | |-------|-------|---------| | `no_malicious_behavior_observed` | 0 | 未检测到任何指标。**并不意味着包是安全的** — 仅表示本次运行未观察到可疑行为。 | | `low_risk` | 1–24 | 检测到微弱信号,但低于可疑阈值。 | | `suspicious` | 25–49 | 存在显著的行为信号;值得仔细审查。 | | `likely_malicious` | 50–74 | 具有高可信度的恶意意图行为证据。 | | `malicious` | 75–100 | 具有强有力的多指标恶意行为证据。 | ### 公告状态 (`advisory_status`) 完全来源于在获取时执行的 OSV.dev 查询。 | 值 | 含义 | |-------|---------| | `none` | OSV 查询成功,但没有公告匹配此包版本。 | | `advisory_hit` | 一个或多个 OSV 公告匹配此包版本。 | | `lookup_failed` | OSV 查询超时或出错;`advisory.advisory_error` 中包含原因。 | 报告中的 `advisory` 字段包含完整的标准化 OSV 结果: `advisory_hit`、`advisory_source`、`advisory_count`、`advisory_ids`、`advisory_summaries`、`advisory_error`。 ### 最终判定 (`final_verdict` / `verdict`) 结合了 `behavioral_verdict` 和 `advisory_status`。`verdict` 是 `final_verdict` 的向后兼容别名。 | `behavioral_verdict` | `advisory_status` | `final_verdict` | `verdict_basis` | |---------------------|------------------|-----------------|-----------------| | `no_malicious_behavior_observed` | `advisory_hit` | `known_vulnerable` | `advisory` | | `low_risk` | `advisory_hit` | `known_vulnerable` | `advisory` | | `suspicious` | `advisory_hit` | `suspicious` | `both` | | `likely_malicious` | `advisory_hit` | `likely_malicious` | `both` | | `malicious` | `advisory_hit` | `malicious` | `both` | | 任意 | `none` 或 `lookup_failed` |(与行为判定相同)| `dynamic` | 公告情报只能升级、绝不会降低最终判定。 ## 局限性与未来工作 **导入时回调架构已修复,语料库重新运行尚待完成。** canary-import-callback 将其 payload 放在 `__init__.py` 中。单容器方法(安装写入 `/scratch/site-packages`,导入时将其添加到 `sys.path` 前面)意味着导入阶段现在可以找到并执行安装时放置的内容。这应该能解决之前的漏报问题。语料库尚未经过重新引爆确认;构建完语料库 sdist 后,运行 `pkgids validate --local-artifacts data/corpus_samples.csv` 进行验证。 **支持的生态系统。** 目前对 PyPI(优先 sdist/wheel、SHA-256 完整性、metadata.json)和 npm 提供深度支持。其他生态系统(如 RubyGems、crates.io 和 Maven)不受支持。 **简单的预测规则。** 当前的启发式规则是:network_activity=True 意味着恶意,安装超时意味着恶意,否则为良性。score.py 中的累加评分模型将其细分为四个层级,但主要的检测信号仍然是行为信号(网络 + 进程活动)。除了归档成员列表外,没有基于 Zeek 的协议分析或静态特征提取。 **无实时数据流。** 该工具由显式的 pkgids detonate 或 pkgids validate 调用驱动。尚未实现与实时包发布流(如 PyPI RSS 或 BigQuery 事件)的集成。 **tcpdump 需要 host root 权限。** pcap 捕获在宿主机网桥接口上使用 tcpdump。如果宿主机用户缺乏必要的权限,则会跳过此操作并发出警告。无论如何,JSONL 设备日志始终会被写入。 **必须安装 gVisor。** 沙箱需要 --runtime runsc。在没有 gVisor 的机器上,请在 config.toml 中设置 runtime = "runc"。这会移除内核级别的隔离,但会保留所有其他隔离层。 ## 负责任的使用 不要在受控环境之外引爆包。相关设备和内部网络确保不会发起真实的互联网调用,但此保证依赖于正确配置的 Docker 和 gVisor。 不要重新分发恶意构件。artifacts/、runs/ 和 corpus/dist/ 目录已被 gitignored(添加到了 .gitignore 中),因为它们可能包含恶意代码。 语料库样本是安全研究包。它们针对的是不存在的域名且不会造成危害,但它们会执行真实的网络代码,应据此予以对待。 ## 运行测试 ``` pytest -v ``` 无需 Docker 即可通过 641 个单元测试。当未配置环境时,17 个依赖 Docker 的测试会自动跳过。
标签:GNU通用公共许可证, IP 地址批量处理, Node.js, Python, 无后门, 沙箱, 请求拦截, 逆向工具, 配置审计