mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-08 08:11:38 +00:00
fix(skill): guard pickle.loads in darwinian-evolver show_snapshot with explicit flag (#29276)
show_snapshot.py unpickled a user-supplied path unconditionally. pickle.loads is equivalent to arbitrary code execution, so a snapshot from an untrusted source = RCE. Require an explicit --i-trust-this-file acknowledgement before calling pickle.loads, and emit a stderr warning when proceeding. Co-authored-by: Jiahui-Gu <jiahuigu@users.noreply.github.com>
This commit is contained in:
parent
93660643a6
commit
0a2ee71ccc
1 changed files with 25 additions and 2 deletions
|
|
@ -25,18 +25,41 @@ def main() -> int:
|
||||||
help="Organism attribute to display. Defaults to the first str field found.",
|
help="Organism attribute to display. Defaults to the first str field found.",
|
||||||
)
|
)
|
||||||
ap.add_argument("--top", type=int, default=None, help="Show only top N by score.")
|
ap.add_argument("--top", type=int, default=None, help="Show only top N by score.")
|
||||||
|
ap.add_argument(
|
||||||
|
"--i-trust-this-file",
|
||||||
|
action="store_true",
|
||||||
|
help=(
|
||||||
|
"Required acknowledgement that the snapshot is from a trusted source. "
|
||||||
|
"pickle.loads executes arbitrary code embedded in the file (RCE) and "
|
||||||
|
"must NEVER be run on snapshots received from untrusted parties."
|
||||||
|
),
|
||||||
|
)
|
||||||
args = ap.parse_args()
|
args = ap.parse_args()
|
||||||
|
|
||||||
if not args.snapshot.exists():
|
if not args.snapshot.exists():
|
||||||
sys.exit(f"snapshot not found: {args.snapshot}")
|
sys.exit(f"snapshot not found: {args.snapshot}")
|
||||||
|
|
||||||
|
if not args.i_trust_this_file:
|
||||||
|
sys.exit(
|
||||||
|
"refusing to unpickle: pickle.loads is equivalent to executing arbitrary "
|
||||||
|
"code from the snapshot file. Only proceed if you created/control this "
|
||||||
|
"file, then re-run with --i-trust-this-file.\n"
|
||||||
|
f" file: {args.snapshot}"
|
||||||
|
)
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"WARNING: unpickling {args.snapshot} — this executes code embedded in the "
|
||||||
|
"file. Only safe for snapshots you produced yourself.",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
|
||||||
# The outer pickle wraps a dict; the inner pickle contains the actual organism
|
# The outer pickle wraps a dict; the inner pickle contains the actual organism
|
||||||
# objects, which must be importable under their original dotted path. If you
|
# objects, which must be importable under their original dotted path. If you
|
||||||
# ran a custom driver, make sure its module is on sys.path before calling this.
|
# ran a custom driver, make sure its module is on sys.path before calling this.
|
||||||
outer = pickle.loads(args.snapshot.read_bytes())
|
outer = pickle.loads(args.snapshot.read_bytes()) # noqa: S301 — gated by --i-trust-this-file
|
||||||
if not isinstance(outer, dict) or "population_snapshot" not in outer:
|
if not isinstance(outer, dict) or "population_snapshot" not in outer:
|
||||||
sys.exit("not a darwinian-evolver snapshot (no population_snapshot key)")
|
sys.exit("not a darwinian-evolver snapshot (no population_snapshot key)")
|
||||||
inner = pickle.loads(outer["population_snapshot"])
|
inner = pickle.loads(outer["population_snapshot"]) # noqa: S301 — gated by --i-trust-this-file
|
||||||
pairs = inner["organisms"] # list of (Organism, EvaluationResult)
|
pairs = inner["organisms"] # list of (Organism, EvaluationResult)
|
||||||
|
|
||||||
print(f"# organisms: {len(pairs)}\n")
|
print(f"# organisms: {len(pairs)}\n")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue