@@ -198,23 +198,23 @@ same seed or fuzzer input.
198198### Integration with Atheris
199199
200200Use the ` PickleMutator ` class for structure-aware fuzzing:
201+ Pass generated pickle bytes to the parser you actually want to fuzz. Do not call
202+ ` pickle.loads() ` on generated data outside a sandbox.
201203
202204``` python
203205import atheris
206+ import sys
204207from pickle_fuzzer.fuzzer import PickleMutator
205- import pickle
206-
207- mutator = PickleMutator(protocol = 3 )
208208
209209@atheris.instrument_func
210210def test_one_input (data : bytes ):
211211 # Generate a valid pickle from fuzzer input within the requested budget
212- pickle_bytes = mutator.mutate(data, max_size = 10000 )
213-
214- try :
215- pickle.loads( pickle_bytes)
216- except Exception :
217- pass # Expected - looking for crashes
212+ input_mutator = PickleMutator( protocol = 3 )
213+ pickle_bytes = input_mutator.mutate(data, max_size = 10000 )
214+
215+ # Call the parser you actually want to fuzz with pickle_bytes here.
216+ # For example: target.parse_pickle(pickle_bytes)
217+ ...
218218
219219atheris.Setup(sys.argv, test_one_input)
220220atheris.Fuzz()
@@ -275,6 +275,9 @@ For detailed fuzzing documentation, see [fuzz/README.md](fuzz/README.md).
275275
276276### Fuzzing Custom Pickle Parsers
277277
278+ Do not point these harnesses at ` pickle.loads() ` unless the unpickling step runs
279+ inside a sandbox you control.
280+
278281``` python
279282# !/usr/bin/env python3
280283import atheris
@@ -283,9 +286,9 @@ from pickle_fuzzer.fuzzer import fuzz_pickle_parser
283286
284287# Your custom pickle parser
285288def my_pickle_parser (data : bytes ):
286- # Your parsing logic here
287- import pickle
288- return pickle.loads(data)
289+ # Replace this with the parser entrypoint you actually want to fuzz.
290+ # Example: return my_project.parse_pickle(data)
291+ ...
289292
290293if __name__ == " __main__" :
291294 # Use structure-aware generation
@@ -300,21 +303,31 @@ if __name__ == "__main__":
300303
301304``` python
302305import atheris
306+ import io
303307import pickle
308+ import sys
304309from pickle_fuzzer.fuzzer import PickleMutator
305310
306- class CustomUnpickler (pickle .Unpickler ):
307- def find_class (self , module , name ):
308- # Custom class resolution logic
309- return super ().find_class(module, name)
311+ _ALLOWED_GLOBALS = {
312+ # Add only the globals your target intentionally supports.
313+ }
310314
311- mutator = PickleMutator(protocol = 3 )
315+
316+ class RestrictedUnpickler (pickle .Unpickler ):
317+ def find_class (self , module , name ):
318+ try :
319+ return _ALLOWED_GLOBALS [(module, name)]
320+ except KeyError as exc:
321+ raise pickle.UnpicklingError(
322+ f " global ' { module} . { name} ' is forbidden in this harness "
323+ ) from exc
312324
313325@atheris.instrument_func
314326def test_custom_unpickler (data : bytes ):
315- pickle_bytes = mutator.mutate(data, max_size = 10000 )
327+ input_mutator = PickleMutator(protocol = 3 )
328+ pickle_bytes = input_mutator.mutate(data, max_size = 10000 )
316329 try :
317- CustomUnpickler (io.BytesIO(pickle_bytes)).load()
330+ RestrictedUnpickler (io.BytesIO(pickle_bytes)).load()
318331 except Exception :
319332 pass
320333
0 commit comments