security: Fix 15 CodeQL alerts — URL sanitization and workflow permissions#108
Merged
security: Fix 15 CodeQL alerts — URL sanitization and workflow permissions#108
Conversation
…sions Resolve all open code scanning alerts: - 3 high-severity: Replace incomplete URL substring checks in verify_badges.py with strict scheme+hostname validation via _is_trusted_host() allowlist and path prefix checks - 12 medium-severity: Add explicit job-level permissions blocks to all jobs in ci.yml, lint.yml, performance.yml, release.yml, and security.yml (principle of least privilege) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Contributor
Reviewer's GuideRefines badge URL validation to use a strict HTTPS + hostname allowlist and path-prefix checks, and tightens GitHub Actions security by adding explicit least-privilege permissions to all relevant workflow jobs. Sequence diagram for strict badge URL verification flowsequenceDiagram
participant BV as BadgeVerifier
participant TH as _is_trusted_host
participant HP as TrustedHostPolicy
participant HTTP as BadgeHost
BV->>TH: _is_trusted_host(url, github_com)
TH->>HP: validate https scheme and hostname in _TRUSTED_HOSTS
HP-->>TH: validation result (true or false)
TH-->>BV: is_trusted
alt trusted_github_actions_badge
BV->>BV: check path startswith /docdyhr/versiontracker/actions/workflows/
BV->>HTTP: GET url
HTTP-->>BV: status (200 or 404)
BV->>BV: mark success if status in [200, 404]
else other_trusted_badge_host
BV->>HTTP: GET url
HTTP-->>BV: status (expected_status)
BV->>BV: mark success if status == expected_status
end
BV->>BV: store result in results list
loop print_summary filtering
BV->>TH: _is_trusted_host(result.url, hostname)
TH-->>BV: is_trusted
BV->>BV: group into github_actions, shields_io, codecov based on hostname and path prefix
end
Class diagram for updated badge verification URL sanitizationclassDiagram
class verify_badges {
<<module>>
_TRUSTED_HOSTS : frozenset
_is_trusted_host(url: str, hostname: str) bool
}
class BadgeVerifier {
results : list
check_badge(name: str, url: str, expected_status: int) dict
print_summary() bool
}
verify_badges <.. BadgeVerifier : uses
class URLParse {
<<external>>
urlparse(url: str) ParseResult
}
BadgeVerifier ..> URLParse : uses
class Requests {
<<external>>
get(url: str) Response
}
BadgeVerifier ..> Requests : uses
%% Highlight new trust model usage
class TrustedHostPolicy {
<<concept>>
requires_https : bool
allowed_hostnames : set
path_prefix_checks : bool
}
verify_badges ..> TrustedHostPolicy : enforces
BadgeVerifier ..> TrustedHostPolicy : validates_badge_urls
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
🔒 Security Analysis ReportSecurity Analysis ReportGenerated: Mon Mar 2 11:48:56 UTC 2026 Bandit Security ScanSafety Check ResultsPip-Audit Results |
Contributor
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- In
verify_badges.py, you’re callingurlparse()multiple times on the same URL within the same logical block (e.g.,check_badgeandprint_summary); consider parsing once and reusing the result to avoid redundant work and make the code easier to read. - The
_is_trusted_host(url, hostname)helper both takes an explicit hostname and checks membership in_TRUSTED_HOSTS; you could simplify the API by deriving the hostname from the URL inside the helper and validating it directly against_TRUSTED_HOSTS, which would also reduce the risk of mismatches between the passed hostname and the parsed one.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `verify_badges.py`, you’re calling `urlparse()` multiple times on the same URL within the same logical block (e.g., `check_badge` and `print_summary`); consider parsing once and reusing the result to avoid redundant work and make the code easier to read.
- The `_is_trusted_host(url, hostname)` helper both takes an explicit hostname and checks membership in `_TRUSTED_HOSTS`; you could simplify the API by deriving the hostname from the URL inside the helper and validating it directly against `_TRUSTED_HOSTS`, which would also reduce the risk of mismatches between the passed hostname and the parsed one.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
py/incomplete-url-substring-sanitization): Replace incomplete URL substring checks inverify_badges.pywith strict scheme+hostname validation via_is_trusted_host()allowlist andstartswith()path prefix checksactions/missing-workflow-permissions): Add explicit job-levelpermissions:blocks to all jobs inci.yml,lint.yml,performance.yml,release.yml, andsecurity.yml— enforcing principle of least privilege per jobFiles changed
.github/verify_badges.py_is_trusted_host()with HTTPS scheme + hostname allowlist.github/workflows/ci.ymlpermissions: contents: readtotestandbuildjobs.github/workflows/lint.ymlpermissions: contents: readtolintjob.github/workflows/performance.yml{}for no-op,contents: readfor checkout).github/workflows/release.ymlvalidate-release,pre-release-checks,build-and-test,verify-release.github/workflows/security.ymlpermissions: contents: read, pull-requests: writetosecurityjobTest plan
🤖 Generated with Claude Code
Summary by Sourcery
Harden badge URL validation and tighten GitHub Actions workflow permissions.
Bug Fixes:
Enhancements:
CI: