forgeguard
Read-only security posture self-check for one explicitly authorized self-hosted Gitea instance.
ForgeGuard gives Gitea operators repeatable evidence about version posture, the fixed-version baseline for CVE-2026-27771, anonymous OCI registry-root behavior, and anonymous responses on a small allowlist of repository/API paths. It uses no exploit probes, performs no internet-wide discovery, and does not request private package contents, manifests, or blobs.
Supported scope in 0.2.2
ForgeGuard 0.2.2 supports self-hosted Gitea. Gitea-specific conclusions require the trusted operator declaration --product gitea; a compatible version endpoint or --known-version alone does not confirm product identity.
Forgejo is not supported. An explicit Forgejo version marker overrides a conflicting Gitea declaration and fails safe as unsupported. ForgeGuard does not apply Gitea version or advisory conclusions to that target.
One invocation accepts one target URL and refuses to run without the operator's --authorized affirmation.
What it checks
- Informational product/version evidence.
- CVE-2026-27771 affected/fixed/unknown version posture for operator-confirmed Gitea.
- Anonymous OCI
/v2/registry-root response posture as an independent observation. - Repository browsing posture on the allowlisted
/explore/repospath. - Anonymous HTTP responses on the two allowlisted repository and user-search API paths.
- Non-overlapping score ownership between the browsing and API observations.
- Markdown and JSON evidence with deterministic scoring and explicit completeness.
Evidence and completeness semantics
PASSmeans evidence supports only the named checked condition.WARNorFAILmeans the named observation produced an actionable result.INFO / UNDETERMINEDmeans evidence was insufficient or ambiguous.- If any core check is undetermined, the final assessment is
value: null,grade: "N/A",assessed: falserather than a normal A–F grade. - HTTP 404, redirects, 429, 5xx and network failures do not become PASS.
- A CVE version result does not prove exploitability, compromise, or data exposure.
- OCI
/v2/HTTP 200 does not prove access to private packages, manifests, or blobs. - ForgeGuard does not infer
REQUIRE_SIGNIN_VIEWor any specific configuration key from HTTP behavior. - Registration posture is not checked in 0.2.2.
What it does not do
- No mass scanning or target discovery.
- No exploit proof of concept.
- No unauthenticated third-party assessment.
- No private repository, package, blob, manifest, or layer retrieval.
- No state-changing remote requests.
- No AI in scoring.
- No security certification, vulnerability oracle, or guarantee of complete security.
Install
python -m pip install forgeguard
Or install the latest source revision:
python -m pip install "git+https://github.com/gexiro-global/forgeguard.git"
For local development:
git clone https://github.com/gexiro-global/forgeguard.git
cd forgeguard
python -m pip install -e ".[dev]"
Raw source-tree execution can inherit metadata from a different installed ForgeGuard distribution. Install the source/editable package before relying on runtime version metadata.
Quickstart
mkdir -p reports
forgeguard scan \
--url https://git.example.com \
--authorized \
--product gitea \
--out ./reports/scan_report.md
Use a version from trusted operator inventory when the authorized version endpoint is intentionally hidden:
forgeguard scan \
--url https://git.example.com/gitea \
--authorized \
--product gitea \
--known-version 1.26.2 \
--format md,json \
--out ./reports/scan_report.md
--out names the Markdown artifact. JSON replaces that suffix with .json;
ForgeGuard refuses a dual-format invocation if both names resolve to the same file.
Omitting --product keeps the product unknown and prevents a Gitea-specific A–F grade, even if a generic version value is returned.
Target URLs must use HTTP or HTTPS, include a hostname, and contain no embedded credentials, query, fragment, decoded ./.. segment, or backslash separator at any of eight decoded layers. Excessive nested encoding is refused. Legal subpaths such as /team/gitea are preserved.
Token handling
Prefer an environment variable so the token is not placed directly in shell history or process arguments:
FORGEGUARD_TOKEN='replace-with-authorized-token' \
forgeguard scan \
--url https://git.example.com \
--authorized \
--product gitea
The backward-compatible --token option remains available, but ForgeGuard emits a security warning because command-line values may be visible in shell history or process listings. Tokens are used only for the authorized version read and are not included in Markdown or JSON reports.
Synthetic before/after
The synthetic example uses an operator-confirmed Gitea target and explicit 401/403 access-control observations. It does not claim that ForgeGuard tested exploitation or private data access.
Before — Gitea 1.26.1, within the affected version range:
Product: gitea 1.26.1 | Score: 80/100 (B)
Summary: critical 0 | high 1 | medium 0 | low 0 | pass 4
Top action: P1 - Upgrade Gitea to >=1.26.2
After — Gitea 1.26.2, at the first fixed release:
Product: gitea 1.26.2 | Score: 100/100 (A)
Summary: critical 0 | high 0 | medium 0 | low 0 | pass 5
Top action: None - no FAIL or WARN findings and all core checks were assessed.
| Finding | Affected version (1.26.1) | First fixed release (1.26.2) |
|---|---|---|
| FG-VER — version evidence | PASS / informational | PASS / informational |
| FG-CVE-27771 — version posture | FAIL / HIGH | PASS |
| FG-SIGNIN / FG-REG / FG-ANON | PASS | PASS |
| Assessment | complete | complete |
| Score | 80/100 (B) | 100/100 (A) |
Full mechanically generated artifacts:
- Affected version Markdown
- Affected version JSON
- First fixed release Markdown
- First fixed release JSON
Scoring
Scoring is deterministic and does not use AI. FG-VER is informational. FG-CVE-27771 is the only finding that penalizes the CVE affected-version condition, so the same version fact is not counted twice.
Likewise, FG-SIGNIN owns only the browser path and FG-ANON owns only the API paths, so one HTTP observation cannot be charged twice.
FAIL findings subtract the full severity weight: critical 40, high 20, medium 10, low 4. WARN findings subtract int(weight * 0.35). A–F grades are emitted only when every core check is assessed. Otherwise the assessment is N/A, not zero and not A.
The score summarizes only ForgeGuard's limited checks. It is not a complete hardening, exploitability, compromise, registration, or private-artifact assessment. See Scoring.
Security and ethics
Run ForgeGuard only on a Gitea instance you own or are explicitly authorized to assess. ForgeGuard uses read-only HTTP GET requests to an exact allowlist and stops at version, root-response, and status-code evidence.
See Authorized Use, Security Policy, and Security Model.
Roadmap
Forgejo support and registration posture are future, product-specific work and are not implemented in 0.2.2. See ROADMAP.md.
License
Apache-2.0. See LICENSE.
Built and maintained by Gexiro Global Enterprises Ltd.
Part of the Gexiro open-source toolkit.
ForgeGuard by Gexiro
Not affiliated with Gitea, Forgejo, Codeberg, GitHub, or GitLab.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file forgeguard-0.2.2.tar.gz.
File metadata
- Download URL: forgeguard-0.2.2.tar.gz
- Upload date:
- Size: 30.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eccf1e18e30005fc1d6caafd218cb78aba243c63ff83fd79b7ed096e739e52dd
|
|
| MD5 |
fee4d98581c5cca9694a124976be6601
|
|
| BLAKE2b-256 |
da5574a10dd3f0c866db326e036147cd35423fb446f2297eee3c8c4d5db28958
|
Provenance
The following attestation bundles were made for forgeguard-0.2.2.tar.gz:
Publisher:
release.yml on gexiro-global/forgeguard
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
forgeguard-0.2.2.tar.gz -
Subject digest:
eccf1e18e30005fc1d6caafd218cb78aba243c63ff83fd79b7ed096e739e52dd - Sigstore transparency entry: 2532437354
- Sigstore integration time:
-
Permalink:
gexiro-global/forgeguard@8f13655e6c48eb5ee0d873b0cd72019e9b87b11e -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/gexiro-global
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8f13655e6c48eb5ee0d873b0cd72019e9b87b11e -
Trigger Event:
release
-
Statement type:
File details
Details for the file forgeguard-0.2.2-py3-none-any.whl.
File metadata
- Download URL: forgeguard-0.2.2-py3-none-any.whl
- Upload date:
- Size: 23.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e88baacbe46c72ce07222e50b5ed4f9e637fa444e2725a7544d8390c1a02ded9
|
|
| MD5 |
72fd822dbdcdb65d8255fbe617332491
|
|
| BLAKE2b-256 |
de87cd096340b67680b8362f430dc0f2d7c811cf553cf0cd057469dcaf4f7112
|
Provenance
The following attestation bundles were made for forgeguard-0.2.2-py3-none-any.whl:
Publisher:
release.yml on gexiro-global/forgeguard
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
forgeguard-0.2.2-py3-none-any.whl -
Subject digest:
e88baacbe46c72ce07222e50b5ed4f9e637fa444e2725a7544d8390c1a02ded9 - Sigstore transparency entry: 2532437424
- Sigstore integration time:
-
Permalink:
gexiro-global/forgeguard@8f13655e6c48eb5ee0d873b0cd72019e9b87b11e -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/gexiro-global
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8f13655e6c48eb5ee0d873b0cd72019e9b87b11e -
Trigger Event:
release
-
Statement type: