|
| 1 | +# Threat model for coverage.py |
| 2 | + |
| 3 | +## What this project does and where untrusted input enters |
| 4 | + |
| 5 | +coverage.py measures code coverage of Python programs. It runs (or is started |
| 6 | +inside) a Python process, records which lines and branches execute, stores the |
| 7 | +results in a SQLite data file (`.coverage`), and produces reports in text, |
| 8 | +HTML, XML (Cobertura), JSON, LCOV, and annotated-source formats. |
| 9 | + |
| 10 | +coverage.py runs with the full privileges of the program being measured. By |
| 11 | +design, the following are **trusted** and are not security boundaries: |
| 12 | + |
| 13 | +- The Python code being measured. coverage.py executes it (`coverage run`) and |
| 14 | + imports it. |
| 15 | +- Configuration files (`.coveragerc`, `setup.cfg`, `tox.ini`, |
| 16 | + `pyproject.toml`) and command-line arguments. |
| 17 | +- Plugins named in configuration. They are imported and run as ordinary |
| 18 | + Python code. |
| 19 | +- Environment variables (`COVERAGE_*`, etc.). |
| 20 | +- The `.pth` file coverage.py may install to measure subprocesses. |
| 21 | + |
| 22 | +Inputs that can reasonably be **less trusted** than the person running |
| 23 | +coverage: |
| 24 | + |
| 25 | +- **Source file contents and file names.** Reports are often generated in CI |
| 26 | + for pull requests from outside contributors and then published (for example |
| 27 | + HTML reports hosted on a web site, or XML/LCOV consumed by other services). |
| 28 | + Source text, file paths, function and class names, and context labels flow |
| 29 | + into report output. These must not be able to inject markup or script into |
| 30 | + HTML reports, break the structure of XML/JSON/LCOV output, or inject terminal |
| 31 | + control sequences into text output. |
| 32 | +- **Data files from other machines.** `coverage combine` reads `.coverage.*` |
| 33 | + SQLite files that are often collected from many CI jobs or downloaded as |
| 34 | + artifacts. A malformed or malicious data file should produce an error, not |
| 35 | + memory corruption, code execution, writing outside of the expected |
| 36 | + directories, or unbounded resource use beyond the size of the input. |
| 37 | +- **Path remapping during combine and reporting** (`[paths]` settings) applied |
| 38 | + to file names recorded in data files. |
| 39 | + |
| 40 | +## Components that matter most / least |
| 41 | + |
| 42 | +Most important: |
| 43 | + |
| 44 | +- `coverage/ctracer/` — the C extension tracer (`coverage.tracer`). It is |
| 45 | + called on every line event of the measured program. Memory-safety bugs here |
| 46 | + (reference-counting errors, use-after-free, buffer overflows) are the highest |
| 47 | + priority. |
| 48 | +- `coverage/html.py`, `coverage/templite.py`, and `coverage/htmlfiles/` — HTML |
| 49 | + report generation and escaping. |
| 50 | +- `coverage/xmlreport.py`, `coverage/jsonreport.py`, `coverage/lcovreport.py`, |
| 51 | + `coverage/report.py`, `coverage/annotate.py` — other report writers. |
| 52 | +- `coverage/sqldata.py`, `coverage/sqlitedb.py`, `coverage/numbits.py`, |
| 53 | + `coverage/data.py` — reading, writing, and combining data files. |
| 54 | +- `coverage/files.py` — path handling, globbing, and remapping. |
| 55 | +- `coverage/phystokens.py`, `coverage/parser.py` — tokenizing and parsing |
| 56 | + source files for reports. |
| 57 | + |
| 58 | +Less important: |
| 59 | + |
| 60 | +- `coverage/pytracer.py` and `coverage/sysmon.py` — pure-Python tracers; bugs |
| 61 | + here are usually correctness issues, not security issues. |
| 62 | +- `coverage/execfile.py`, `coverage/plugin_support.py`, `coverage/config.py`, |
| 63 | + `coverage/tomlconfig.py` — they process trusted input by design. |
| 64 | + |
| 65 | +Out of scope: |
| 66 | + |
| 67 | +- `lab/`, `ci/`, `doc/`, `igor.py`, and `tests/` — developer tooling, not |
| 68 | + shipped in the package. |
| 69 | +- The vendored JavaScript and CSS in `coverage/htmlfiles/` beyond how |
| 70 | + coverage.py fills in the data it renders. |
| 71 | + |
| 72 | +## How to exercise it |
| 73 | + |
| 74 | +- The checkout is in `/src`. The project is installed editable in the tox |
| 75 | + environment `/src/.tox/py313`, which is first on `PATH`, with the C |
| 76 | + extension built in place. `coverage` is the command-line entry point. |
| 77 | +- `tox -e py313` runs the full test suite with each tracer: the C tracer |
| 78 | + (`ctrace`), the Python tracer (`pytrace`), and `sys.monitoring` (`sysmon`). |
| 79 | + It removes the C extension to test the other tracers; rebuild it with |
| 80 | + `python setup.py build_ext --inplace`. |
| 81 | +- `python igor.py test_with_core ctrace` runs the tests with just the C |
| 82 | + tracer. Standard pytest arguments can be added, for example `-k html`. |
| 83 | +- Typical flow to produce reports from a program: |
| 84 | + `coverage run --branch prog.py && coverage html && coverage xml && coverage json && coverage lcov`. |
| 85 | +- To exercise combining: create several data files with `coverage run -p` and |
| 86 | + run `coverage combine`. |
| 87 | +- Tests that need network access or a non-root user are skipped or marked |
| 88 | + xfail. |
| 89 | + |
| 90 | +## How you rate severity |
| 91 | + |
| 92 | +- Memory corruption in the C tracer that a measured program can trigger |
| 93 | + through ordinary Python code: high. (The measured program is trusted, but |
| 94 | + coverage.py should never crash it.) |
| 95 | +- Script or markup injection into HTML reports from source contents, file |
| 96 | + names, or data files: high. |
| 97 | +- Code execution, or reading/writing files outside the expected locations, |
| 98 | + triggered by a crafted data file during combine or reporting: high. |
| 99 | +- Corrupting the structure of XML, JSON, or LCOV output, or terminal control |
| 100 | + sequence injection in text output: medium. |
| 101 | +- Crashes or excessive resource use from malformed data files: low. |
| 102 | +- Anything that requires control of configuration, plugins, environment |
| 103 | + variables, or the measured code itself to cause effects that code could |
| 104 | + already cause directly: not a vulnerability. |
| 105 | + |
| 106 | +## Anything to leave alone |
| 107 | + |
| 108 | +- Use of `exec`, `compile`, and imports to run the measured program and |
| 109 | + plugins is intentional. |
| 110 | +- Non-cryptographic hashing (for example for file fingerprints) is |
| 111 | + intentional and is marked `usedforsecurity=False`. |
| 112 | +- SQL in `sqldata.py` is built from internal constants; table and column names |
| 113 | + are not user-controlled. |
0 commit comments