forked from pyca/cryptography
-
Notifications
You must be signed in to change notification settings - Fork 0
Cybersecurity analysis report + fork hardening #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
4c86398
Add cybersecurity reinforcement analysis report
claude 0a1c089
Harden fork against accidental release-pipeline runs
claude f631adc
Skip ppc64le CI legs on forks
claude d71e3c6
Fix workflow validation error; drop ppc64le legs on fork
claude 468cded
Skip scheduled linkcheck runs on forks
claude 77e6503
Ignore CI-hostile hosts in docs linkcheck
claude File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| # Default owners for everything in this fork. | ||
| * @duksh |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| # Security Policy | ||
|
|
||
| This repository is a fork of [pyca/cryptography](https://github.com/pyca/cryptography). | ||
| It does **not** publish releases, wheels, or packages anywhere. If you obtained | ||
| `cryptography` from PyPI or a distribution, it did not come from this fork. | ||
|
|
||
| ## Reporting a vulnerability in the cryptography library | ||
|
|
||
| Vulnerabilities in the library itself should be reported **upstream**, following | ||
| the upstream security policy: https://cryptography.io/en/latest/security/ | ||
| (report privately via https://github.com/pyca/cryptography/security/advisories/new — | ||
| not in a public issue tracker). | ||
|
|
||
| ## Reporting an issue specific to this fork | ||
|
|
||
| For issues that exist only in this fork (for example, its CI configuration or | ||
| repository setup), please open a private security advisory on this repository: | ||
| https://github.com/duksh/cryptography/security/advisories/new | ||
|
|
||
| ## Supported versions | ||
|
|
||
| This fork tracks the upstream `main` branch and ships nothing; there are no | ||
| supported release versions here. See the upstream policy for supported versions | ||
| of the actual library. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,217 @@ | ||
| # Security Analysis: duksh/cryptography | ||
|
|
||
| A cybersecurity reinforcement analysis of this repository (a fork of | ||
| [pyca/cryptography](https://github.com/pyca/cryptography), v50.0.0-dev1, synced with | ||
| upstream as of 2026-07-22). Three areas were audited: CI/supply-chain posture, the | ||
| code-level cryptographic surface, and testing/fuzzing assurance. | ||
|
|
||
| ## Executive summary | ||
|
|
||
| The upstream project is one of the best-hardened codebases in the Python ecosystem, and | ||
| this fork inherits that posture: SHA-pinned Actions, least-privilege workflow permissions, | ||
| OIDC trusted publishing with PEP 740 attestations, hash-pinned build requirements, | ||
| memory-safe Rust parsers, an enforced 100% coverage gate, and differential test vectors | ||
| run across five TLS backends. The most actionable reinforcement opportunities are | ||
| **fork-specific**: the release/publish pipeline is not guarded against running in a fork, | ||
| and the vulnerability-reporting channel points at the upstream project. Beyond that, | ||
| there are meaningful gaps in dependency auditing, code scanning, fuzzing, and a handful of | ||
| code-level hardening items. | ||
|
|
||
| Findings are prioritized P1 (act first) through P4. | ||
|
|
||
| ## Baseline strengths (verified) | ||
|
|
||
| | Area | Evidence | | ||
| |---|---| | ||
| | Action pinning | Every third-party action pinned to a full commit SHA (e.g. `ci.yml:72`, `pypi-publish.yml:60`) | | ||
| | Workflow permissions | Top-level `permissions: contents: read` in all main workflows; job-level elevation only where needed (`pypi-publish.yml:31-33`) | | ||
| | Checkout hygiene | `persist-credentials: false` on test/build checkouts; no `pull_request_target`; no self-hosted runners | | ||
| | Publishing | OIDC Trusted Publishing (`uv publish --trusted-publishing=always`, `pypi-publish.yml:77`); no PyPI token secret exists; PEP 740 attestations via `astral-sh/attest-action`; SBOM embedded in wheels (`wheel-builder.yml:151`) | | ||
| | Dependency pinning | `.github/requirements/build-requirements.txt` and `uv-requirements.txt` hash-pinned and consumed with `--require-hashes`; `Cargo.lock` committed with checksums; daily Dependabot for actions/cargo/uv incl. transitive deps | | ||
| | Memory safety | ASN.1/X.509/key-parsing crates are `#![forbid(unsafe_code)]` (`cryptography-x509`, `cryptography-x509-verification`, `cryptography-key-parsing`); all unsafe blocks require `// SAFETY:` comments (`clippy::undocumented_unsafe_blocks` denied); `overflow-checks = true` in release (`Cargo.toml`) | | ||
| | Test assurance | Enforced 100% combined Python+Rust coverage (`.github/bin/merge_rust_coverage.py:138-142`); wycheproof + x509-limbo vectors (pinned refs) in every matrix leg; matrix spans OpenSSL 3.0.x–master, LibreSSL, BoringSSL, AWS-LC, FIPS, `no-legacy`, free-threaded Python | | ||
| | Weak-crypto quarantine | Legacy ciphers isolated in `hazmat/decrepit/`; constant-time compares via `hmac.compare_digest` / `CRYPTO_memcmp`; OpenSSL < 3.0 is a hard compile error (`src/_cffi_src/openssl/cryptography.py:55-60`) | | ||
|
|
||
| ## P1 — Fork-specific risks | ||
|
|
||
| ### 1.1 The publish pipeline is not owner-guarded | ||
|
|
||
| All scheduled bot workflows are gated with `if: github.repository_owner == 'pyca'` | ||
| (`auto-close-stale.yml:9`, `lock.yml:9`, `boring-open-awslc-bump.yml:13`, | ||
| `downstream-version-bump.yml:13`, `x509-limbo-version-bump.yml:13`), so they no-op on this | ||
| fork. The **release path is not**: | ||
|
|
||
| - `wheel-builder.yml:11-13` triggers on any tag push matching `*.*` / `*.*.*` — no owner | ||
| guard. Pushing a tag like `1.0` to this fork starts a full multi-platform wheel build. | ||
| - `pypi-publish.yml:14-16` chains from Wheel Builder completion via `workflow_run`, and | ||
| its gate (`pypi-publish.yml:30`) checks only the event type and conclusion — not the | ||
| repository owner. It then requests `id-token: write` + `attestations: write` and runs | ||
| `uv publish --trusted-publishing=always`. | ||
|
|
||
| On this fork the publish would only succeed if a PyPI Trusted Publisher were ever | ||
| configured for `duksh/cryptography` — safety currently rests entirely on that PyPI-side | ||
| absence, with no in-repo defense. | ||
|
|
||
| **Recommendation:** add `if: github.repository_owner == 'pyca'` (or the fork owner, if | ||
| the fork intends to publish under a different name) to the `wheel-builder.yml` tag | ||
| trigger jobs and the `pypi-publish.yml` publish job, and/or disable these workflows in | ||
| the fork's Actions settings. | ||
|
|
||
| ### 1.2 No valid vulnerability-reporting channel | ||
|
|
||
| - There is no `SECURITY.md`; the policy in `docs/security.rst:60-67` directs reporters to | ||
| the **upstream pyca** advisory page (`pyca/cryptography/security/advisories/new`). | ||
| - There is no `CODEOWNERS` file. | ||
|
|
||
| **Recommendation:** add a root `SECURITY.md` stating where issues in *this fork* should | ||
| be reported (or explicitly deferring to upstream and stating the fork ships no releases), | ||
| and a `CODEOWNERS` if more than one person maintains the fork. | ||
|
|
||
| ### 1.3 Third-party code execution in CI | ||
|
|
||
| `ci.yml:402-451` (downstream tests: paramiko, twisted, mitmproxy, scapy, certbot, | ||
| aws-encryption-sdk, sigstore-python) and `benchmark.yml:38` check out and execute | ||
| external repositories' code in this repo's CI context. Refs are pinned to commit SHAs and | ||
| the token is read-only, so exposure is limited — but on a fork this is unnecessary attack | ||
| surface and compute. | ||
|
|
||
| **Recommendation:** owner-gate or disable the downstream and benchmark jobs on the fork. | ||
|
|
||
| ## P2 — Supply-chain hardening | ||
|
|
||
| ### 2.1 One unhashed install path — and it is in the publish job | ||
|
|
||
| `ci-constraints-requirements.txt` is version-pinned but **not** hash-pinned (unlike the | ||
| `.github/requirements/*.txt` files). It is used to bootstrap `uv`/`nox` in CI | ||
| (`ci.yml:150,212,478`) and, notably, in the publish job (`pypi-publish.yml:58`). | ||
|
|
||
| **Recommendation:** compile it with `--generate-hashes`, or bootstrap the publish job | ||
| from the already-hashed `.github/requirements/uv-requirements.txt`. | ||
|
|
||
| ### 2.2 No dependency-audit gates | ||
|
|
||
| `Cargo.lock` is committed, but there is no `cargo-deny` / `cargo-audit` / `cargo-vet` | ||
| configuration or CI job for Rust advisory/license checking, and no `pip-audit` job — | ||
| even though `docs/security.rst:8-13` recommends osv.dev tooling to downstream users. | ||
|
|
||
| **Recommendation:** add a scheduled + PR workflow running `cargo deny check advisories` | ||
| (plus optional `pip-audit` against the hashed requirements files). | ||
|
|
||
| ### 2.3 No code-scanning workflows | ||
|
|
||
| No CodeQL, semgrep, or OpenSSF Scorecard integration exists in the repository. | ||
|
|
||
| **Recommendation:** add CodeQL (Python; Rust once stable) and the Scorecard action with | ||
| results published to the Security tab. Scorecard also directly measures several items in | ||
| this report (pinning, token permissions, fuzzing, SAST). | ||
|
|
||
| ### 2.4 Minor items | ||
|
|
||
| - `pypi-publish.yml:19` defines `PUBLISH_REQUIREMENTS_PATH=.github/requirements/publish-requirements.txt`, | ||
| which **does not exist** and is never used — dead reference; remove it or restore a | ||
| hash-pinned publish requirements file. | ||
| - `dtolnay/rust-toolchain` is SHA-pinned but lacks a version comment (`ci.yml:85`), | ||
| making drift review harder. | ||
| - `dependabot.yml` sets `open-pull-requests-limit: 1024` per ecosystem — effectively | ||
| unbounded automated-PR volume. | ||
|
|
||
| ## P3 — Code-level hardening | ||
|
|
||
| ### 3.1 No secret zeroization | ||
|
|
||
| There is no `zeroize` crate usage (0 references in `Cargo.toml`/`Cargo.lock`) and no | ||
| explicit cleansing of key or plaintext buffers in `src/rust`. Secret material relies on | ||
| OpenSSL's internal handling and Rust drop semantics; owned intermediate buffers (derived | ||
| keys, seeds, decrypted PKCS#12 material) are not scrubbed. | ||
|
|
||
| **Recommendation:** adopt `zeroize` (or explicit `OPENSSL_cleanse` calls through the FFI | ||
| shim) for owned secret buffers, starting in `cryptography-openssl`. | ||
|
|
||
| ### 3.2 Rust lint gaps | ||
|
|
||
| - No `#![deny(unsafe_op_in_unsafe_fn)]` anywhere — unsafe operations inside `unsafe fn` | ||
| bodies are not individually flagged. | ||
| - No `[workspace.lints]` table; lint policy is per-crate inner attributes, so a new crate | ||
| could silently omit them. There are 66 unsafe blocks across 16 files (concentrated in | ||
| the `cryptography-openssl` FFI shim: `mlkem.rs`, `mldsa.rs`, `aead.rs`, `hmac.rs`). | ||
|
|
||
| **Recommendation:** add a workspace lints table with `unsafe_op_in_unsafe_fn = "deny"` | ||
| and inherit it in all crates; keep `forbid(unsafe_code)` in every crate that doesn't | ||
| strictly need FFI. | ||
|
|
||
| ### 3.3 Legacy algorithm exposure gaps | ||
|
|
||
| - `CAST5`, `IDEA`, `SEED`, and `Blowfish` are re-exported from | ||
| `src/cryptography/hazmat/primitives/ciphers/algorithms.py:8-28` **without** deprecation | ||
| wrappers — only `Camellia`, `ARC4`, and `TripleDES` warn (`algorithms.py:70-103`). | ||
| - `MD5` (`hashes.py:281`), `SHA1` (`hashes.py:101`), and DSA key generation | ||
| (`dsa.py:166-179`) carry no deprecation gating. | ||
| - RSA generation floor is 1024 bits (`rsa.py:180-181`), below the modern 2048 | ||
| recommendation; key loading enforces no floor. | ||
|
|
||
| **Recommendation:** extend `utils.deprecated` wrappers to the remaining decrepit | ||
| re-exports; consider a `CryptographyDeprecationWarning` on RSA generation below 2048 and | ||
| on DSA generation. (For a fork, these could also be hard errors if no legacy | ||
| compatibility is needed.) | ||
|
|
||
| ### 3.4 No minimum-version assertion for alternative backends | ||
|
|
||
| Only OpenSSL proper has a hard compile-time floor | ||
| (`src/_cffi_src/openssl/cryptography.py:55-60`). LibreSSL, BoringSSL, and AWS-LC are | ||
| detected by feature cfg only (`src/rust/build.rs:36-49`) — an old LibreSSL could compile | ||
| without any version assertion. | ||
|
|
||
| **Recommendation:** add explicit minimum-version `#error`/build-fail gates for the | ||
| alternative backends matching what CI actually tests. | ||
|
|
||
| ### 3.5 Documented validation bypass (informational) | ||
|
|
||
| `unsafe_skip_rsa_key_validation` (`src/rust/src/backend/keys.rs:12-26`) is a public | ||
| keyword-only flag that skips RSA key consistency checks on load. It is clearly named and | ||
| defaults to `False`; no change proposed, but any downstream code setting it should be | ||
| audited. | ||
|
|
||
| ## P4 — Assurance depth | ||
|
|
||
| ### 4.1 No fuzzing | ||
|
|
||
| No cargo-fuzz/libFuzzer targets, no OSS-Fuzz or ClusterFuzzLite configuration exist in | ||
| the repo. The hand-rolled ASN.1 parsers (X.509 certificates/CRLs/CSRs, PKCS#7, PKCS#12) | ||
| are memory-safe Rust, but panics and logic/differential bugs remain findable by fuzzing. | ||
|
|
||
| **Recommendation:** add `cargo fuzz` targets for `load_der_x509_certificate`, | ||
| `load_der_x509_crl`, `load_der_x509_csr`, and the PKCS#7/PKCS#12 parsers, and wire | ||
| ClusterFuzzLite into CI for PR-time fuzzing. | ||
|
|
||
| ### 4.2 No sanitizer CI legs | ||
|
|
||
| No ASAN/UBSAN/MSAN jobs exist; memory-safety assurance at the CFFI/OpenSSL boundary rests | ||
| on Rust's guarantees plus backend diversity. | ||
|
|
||
| **Recommendation:** add one ASAN+UBSAN matrix leg (nightly Rust `-Zsanitizer=address` | ||
| with an ASAN-built OpenSSL) on a scheduled workflow if PR latency is a concern. | ||
|
|
||
| ### 4.3 Minor | ||
|
|
||
| `mypy` is strict-ish but not maximal (`pyproject.toml:152-164` — no | ||
| `disallow_untyped_defs`). | ||
|
|
||
| ## Remediation roadmap | ||
|
|
||
| | # | Action | Priority | Effort | | ||
| |---|---|---|---| | ||
| | 1 | Owner-guard `wheel-builder.yml` + `pypi-publish.yml` (or disable on fork) | P1 | Small | | ||
| | 2 | Add `SECURITY.md` (+ `CODEOWNERS`) for the fork | P1 | Small | | ||
| | 3 | Owner-gate downstream/benchmark third-party CI jobs | P1 | Small | | ||
| | 4 | Hash-pin `ci-constraints-requirements.txt`; fix dead `PUBLISH_REQUIREMENTS_PATH` | P2 | Small | | ||
| | 5 | Add `cargo deny check advisories` (+ optional `pip-audit`) workflow | P2 | Small | | ||
| | 6 | Add CodeQL + OpenSSF Scorecard workflows | P2 | Small | | ||
| | 7 | Workspace `[lints]` with `unsafe_op_in_unsafe_fn = "deny"` | P3 | Small | | ||
| | 8 | Deprecation wrappers for CAST5/IDEA/SEED/Blowfish re-exports; DSA/small-RSA warnings | P3 | Medium | | ||
| | 9 | Minimum-version gates for LibreSSL/BoringSSL/AWS-LC | P3 | Medium | | ||
| | 10 | Adopt `zeroize` for owned secret buffers | P3 | Medium | | ||
| | 11 | cargo-fuzz targets + ClusterFuzzLite for the ASN.1/PKCS parsers | P4 | Medium | | ||
| | 12 | Scheduled ASAN/UBSAN CI leg | P4 | Medium | | ||
|
|
||
| Items 8–10 change library behavior/internals and are best contributed upstream rather | ||
| than carried as fork-only patches. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Update the report to reflect this PR’s remediation.
These sections still state that publishing is unguarded, no
SECURITY.md/CODEOWNERSexists, and benchmark/downstream jobs run on forks. The final workflows and documentation now implement those controls, so either mark these findings as remediated or label the report as a pre-remediation snapshot; otherwise it documents an incorrect security posture.Also applies to: 37-78
🤖 Prompt for AI Agents