Skip to main content
Glama
Baneado98

ci-sentinel

by Baneado98

ci-sentinel πŸ›‘οΈ

Security auditor for SEVEN CI ecosystems β€” GitHub Actions, GitLab CI/CD, Jenkins, CircleCI, Azure Pipelines, Bitbucket Pipelines and Travis CI β€” finds the supply-chain and injection flaws a YAML linter can't see, before an attacker's pull/merge request runs code with your repository secrets.

Available as an MCP server (for Claude / Cursor / any agent) and a pay-per-call HTTP API (x402 USDC or a prepaid card key).

Give it your .github/workflows/*.yml, .gitlab-ci.yml, Jenkinsfile, .circleci/config.yml, azure-pipelines.yml, bitbucket-pipelines.yml and/or .travis.yml (each file is auto-routed to the right analyzer) and get a CRITICAL / VULNERABLE / RISKY / HARDENED verdict with the exact flaws.

What it catches that a linter can't

Class

What ci-sentinel does

πŸ’‰ Expression injection (inter-step / inter-job taint)

Taints untrusted ${{ github.event.* }} (issue/PR title, body, comment, review, branch name, commit message, label name, fork repo identity, edited-from values) to a run: shell or actions/github-script sink β€” and follows it across steps.<id>.outputs.*, needs.<job>.outputs.*, env: vars, matrix values and reusable-workflow inputs.*. An attacker who hides the untrusted value behind an intermediate output is still caught; a per-file grep is not.

🎭 Pwn requests

pull_request_target / workflow_run that check out untrusted fork code in the privileged, secret-bearing context = arbitrary code execution with your secrets.

πŸ”‘ Token permissions

Excessive GITHUB_TOKEN scopes (write-all, contents:write, id-token:write), missing permissions: blocks, and secrets exposed to untrusted triggers.

πŸ” Reusable workflows

workflow_call callers passing untrusted data across the boundary as inputs.*, and secrets: inherit handing the full secret set to a reusable workflow on an untrusted trigger.

πŸ“Œ Action pinning

Third-party actions (and reusable-workflow uses:) on mutable tags/branches instead of a commit SHA (the tj-actions/changed-files-style hijack), resolved through the transitive action graph.

πŸ–₯️ Self-hosted RCE

Self-hosted runners reachable from public-repo PRs (RCE on your own infra), and OIDC id-token trust misuse.

…and the same depth for GitLab CI/CD (.gitlab-ci.yml)

Class

What ci-sentinel does

πŸ’‰ CI-variable injection

Taints untrusted GitLab variables (CI_COMMIT_REF_NAME/BRANCH/TAG, CI_MERGE_REQUEST_TITLE/DESCRIPTION/SOURCE_BRANCH_NAME, commit message/author, triggering-user fields) interpolated into script: β€” following the taint through variables: and extends: templates. Knows the SAFE vars (CI_COMMIT_SHA, CI_MERGE_REQUEST_IID, CI_PROJECT_ID, …) so it doesn't flag every $CI_.

🎭 Fork merge-request pwn

Jobs reachable from fork MR pipelines (merge_request_event, only: merge_requests) that carry secrets / a broad CI_JOB_TOKEN / id_tokens (OIDC), or that run privileged work (deploy/publish/kubectl/terraform) with no when: manual gate.

πŸ“¦ include: supply-chain

include: from a remote URL or another project/component on a moving (non-SHA) ref β€” foreign pipeline code merged into yours.

☣️ Artifact / cache poisoning

An untrusted job writes an artifact/cache that a privileged downstream job consumes and executes (needs:/dependencies: or a shared cache path) β€” a cross-job and cross-pipeline escalation.

…and five more CI systems, same taint model

Ecosystem

What ci-sentinel catches

πŸ”§ Jenkins (Jenkinsfile)

Command injection from params.* / env.CHANGE_* / ghprb* / SCM data into sh/bat/powershell (through environment{} bindings); credential-leak (credentials()/withCredentials printed or baked into a GString); Groovy evaluate()/load RCE; missing input() approval gate; unsafe agent any.

β­• CircleCI (.circleci/config.yml)

Shell injection from << pipeline.git.branch/tag >> / pipeline parameters into run:; unpinned orbs (@volatile / bare major); fork-PR context secret exposure with no type: approval gate; privileged deploy with no approval.

🟦 Azure Pipelines (azure-pipelines.yml)

Macro injection from $(Build.SourceBranch) / $(System.PullRequest.SourceBranch) / commit message into script:/bash:/pwsh:; untrusted templates from a foreign repo resource; fork variable-group secret exposure; unpinned repository resources.

πŸͺ£ Bitbucket Pipelines (bitbucket-pipelines.yml)

Shell injection from $BITBUCKET_BRANCH / $BITBUCKET_TAG / $BITBUCKET_PR_DESTINATION_BRANCH / commit message expanded unquoted into script:; secured/deployment-variable exposure on externally-triggerable PR pipelines; unpinned pipes (:latest); deployments with no trigger: manual gate.

🚦 Travis CI (.travis.yml)

Shell injection from $TRAVIS_BRANCH / $TRAVIS_PULL_REQUEST_BRANCH / $TRAVIS_COMMIT_MESSAGE expanded unquoted into a lifecycle hook; secure-env PR/fork secret exposure; deploy: stages with no on: branch/condition gate.

…plus two deep cross-domain detectors a one-shot agent can't replicate

Detector

What ci-sentinel catches

☁️ OIDC cloud-trust misconfiguration (Terraform / CloudFormation / GCP workload-identity / Azure federated-credential)

Models the cloud half of CI OIDC: the trust policy of the IAM role / WIF pool / federated app. Flags a sub condition with a broad wildcard (repo:org/*, repo:*), no sub condition at all (any workflow on the issuer assumes the role), a repo pinned but ref/environment unpinned (any branch assumes), the bare pull_request subject (fork-reachable), or an unpinned aud. Then correlates the IaC trust with the CI side (a workflow that mints id-token reachable from an untrusted trigger) and escalates to critical when the chain is reachable end-to-end. No single-file linter catches this β€” it spans the CI claim and the cloud trust policy.

πŸ”§ Jenkins shared libraries (@Library β†’ vars/*.groovy)

Taints an untrusted pipeline value (PR title / branch / build parameter) passed to a shared-library global-var step through the library's call() interior to an internal sh/bat sink β€” the Jenkins parity of orb/template/composite-action cross-file taint, invisible when reading only the Jenkinsfile. Also flags @Library imports on a mutable ref (a branch / default version) as supply-chain risk.

Each analyzer knows the SAFE variables (SHAs, numeric ids, trusted slugs β€” BITBUCKET_COMMIT, TRAVIS_PULL_REQUEST, pipeline.git.revision, …) and the SAFE OIDC trusts (sub pinned to repo:org/repo:ref:refs/heads/main / :environment:prod with aud set) so it doesn't flag every $VAR or every trust. Zero false positives on hardened configs.

It is a real static analyzer: a line-aware workflow YAML parser β†’ a model of triggers/jobs/steps/permissions/actions/outputs/needs β†’ an inter-step/inter-job taint resolver + permission + supply-chain detectors β†’ a scored verdict with per-finding file:line, the full taint path, concrete remediation, and a SARIF 2.1.0 report (with codeFlows) you can upload to GitHub code scanning.

…and it doesn't just flag β€” it FIXES, and it GRADES

Premium

What you get

πŸ”§ Auto-remediation (the exact fix)

For each finding ci-sentinel produces the concrete change: the corrected YAML/Groovy snippet and a unified diff you can apply β€” pin the action/orb/pipe to an immutable SHA/version, env-bind + quote the injected expression, drop write-all to least privilege, insert the manual/approval gate, pin the OIDC sub/aud, move the hardcoded secret to the store (and rotate it). Not "you have a bug" but "change THIS to THIS", with a confidence label (exact / template / guided) so you know what's drop-in vs. what needs a value filled. Findings carry a stable fingerprint for de-duplication, and the SARIF results carry inline fixes.

πŸ“‹ Compliance scorecard (A–F)

A CIS-like CI security benchmark scored A–F with a PASS / FAIL / WARN / N/A breakdown per control (least privilege, component pinning, no secrets to forks, no self-hosted on public PRs, OIDC pinned, no hardcoded secrets, no pwn checkout, gated deploys, no injection, no cross-job poisoning). Each control lists the finding ids that drove its verdict β€” defensible to a security team. A directly-exploitable critical flaw caps the grade (one open RCE/secret-exfil path dominates the posture).

πŸ›°οΈ Live threat-intelligence feed (the data moat)

Every uses: / orb / pipe in your config is checked against a live, server-side feed of KNOWN-compromised CI components, ingested on a cron from public sources β€” OSV.dev and the GitHub Security Advisory database (ecosystem=actions) β€” and merged onto a curated seed of the flagship incidents (tj-actions/changed-files CVE-2025-30066, reviewdog/action-setup CVE-2025-30154 and its transitive dependents, the aquasecurity/trivy-action tag force-push, Ultralytics). It knows that tj-actions/changed-files@v45 is poison and that the same action SHA-pinned to a clean commit or upgraded to @v46 is safe β€” a distinction a static YAML scan or a local linter cannot make, because it has no feed. The feed lives only on the hosted server (the thin client never carries it); GET /feed/status surfaces its freshness. A live reputation signal (stars / last-commit / archived / does-the-repo-still-resolve) additionally flags archived/abandoned components and dangling references that are takeover-bait. This is the access-moat that justifies the hosted, paid model: the value is the live DATA, not the compute.

πŸͺ€ Tag-rewrite & imposter detection (live refβ†’commit)

Give ci-sentinel the commit SHA you expected a mutable ref to be (from your lockfile/SBOM) and it resolves what the tag currently points at upstream β€” flagging a tag-rewrite / force-push (@v2 now runs a different commit than you reviewed β€” the exact tj-actions attack), a deleted/dangling ref, or a suspiciously recent move. It also pairs typosquat detection with the live reputation signal to confirm impersonation β€” actons/checkout (a near-miss of actions) whose repo is a freshly-stood-up, low-star or dangling imposter β€” vs. a legitimately-named small fork (no false positive). And because the feed is keyed by component identity, a compromised action is caught no matter which CI system references it (cross-CI) β€” the piece a mono-CI scanner structurally can't have.

Related MCP server: GuardX

MCP server (free)

{
  "mcpServers": {
    "ci-sentinel": { "command": "npx", "args": ["-y", "ci-sentinel-mcp"] }
  }
}

Tool: audit_ci_security. Pass files (a map of workflow filename β†’ YAML) or source (one workflow). The free tier returns the verdict and how many issues of each kind were found.

Deep audit (deep: true) β€” two ways to pay

The deep audit returns every finding with file:line, the full inter-step/ inter-job injection taint path, the transitive action supply-chain graph, a concrete fix (corrected snippet + unified diff) per finding, an A–F compliance scorecard with a per-control breakdown, and a SARIF 2.1.0 document with inline fixes (uploadable to GitHub code scanning via github/codeql-action/upload-sarif).

  • πŸ’³ Card (Stripe) β€” buy a prepaid key at https://ci-sentinel.vercel.app/pro/checkout, then set "env": { "CI_SENTINEL_KEY": "<key>" } in your MCP config.

  • πŸͺ™ x402 (USDC) β€” AI agents pay per call automatically (USDC on Base), no signup.

HTTP API

POST /audit          # free, rate-limited β€” verdict + per-severity counts
POST /pro/audit      # deep β€” pay-per-call (x402) or Authorization: Bearer <key>
POST /mcp            # MCP-over-HTTP (free)
GET  /presence       # live active sessions (last 5 min)
GET  /                # this landing page
curl -X POST https://ci-sentinel.vercel.app/audit \
  -H 'Content-Type: application/json' \
  -d '{"files":{".github/workflows/ci.yml":"name: CI\non: pull_request_target\n..."}}'

Why hosted? (the moat)

The npm package is a thin client: it runs no analysis locally. The parser, taint engine, action-graph resolver and detector knowledge base run server-side only, behind the paywall β€” so the premium material (findings, evidence, taint paths, remediation) never lands on the caller's machine. A npm pack ships only dist/mcp.js, dist/mcpServer.js and dist/types.js; the engine is never in the tarball (verified automatically by npm run test:moat).

How the live feed stays live (the update pipeline)

The threat-intelligence feed is ingested, not hard-coded. A periodic job runs server-side:

  1. Fetch advisories from two public sources (no paid keys):

    • GitHub Security Advisory DB β€” GET /advisories?ecosystem=actions (public; GITHUB_TOKEN only raises the rate limit, it is not required).

    • OSV.dev β€” the GitHub Actions ecosystem, queried for the components we already track plus everything GHSA just surfaced (so OSV enriches them).

  2. Normalize each advisory into a ThreatRecord β€” owner/name split, incident class inferred from the advisory text (tag-rewrite / maintainer-compromise / malicious / CVE…), severity bucketed, the affected version range parsed into a selector, the fixed version captured (so an upgraded pin does not fire).

  3. Merge the rows onto the curated seed (ingestFeed: union refs, keep the worst severity, widen the affected range, de-dup by identity).

  4. Store the snapshot in Cloudflare KV. Every /pro/audit reads it back via kvFeedProvider, falling back to the compiled seed if KV is cold β€” so the detector is never blocked and never worse than the static baseline.

# run the refresh once (live: hits the real public APIs)
node scripts/refreshFeed.mjs
# dry run with no network (produces the seed-only snapshot)
CI_SENTINEL_NO_NET=1 node scripts/refreshFeed.mjs

Schedule it with Vercel Cron ({ "path": "/internal/refresh-feed", "schedule": "0 */6 * * *" }, guarded by FEED_REFRESH_TOKEN) or a scheduled GitHub Action that runs node scripts/refreshFeed.mjs. GET /feed/status reports the live snapshot's version, generatedAt and record count β€” the public freshness proof. None of this ships in the npm client.

Development

npm install
npm run build          # tsc
npm test               # engine + parser + taint + SARIF + autofix + compliance + corpus tests (851 checks)
npm run test:moat      # lock-proof: tarball ships no engine, deep degrades w/o pay
npm run dev:http       # local HTTP server (FORCE_LISTEN)

Heuristic static analysis of the workflow YAML you provide β€” it cannot see repo-level default token permissions, branch protections or org policy, and does not execute the pipeline. Treat findings as leads to verify.

Source & docs: https://github.com/Baneado98/ci-sentinel Β· MIT

Available Tools

2 tools
audit_ci_securityAInspect

Audit GitHub Actions, GitLab CI/CD, Jenkins, CircleCI, Azure Pipelines, Bitbucket Pipelines AND Travis CI for security flaws BEFORE you merge or trust them β€” SEVEN CI ecosystems in one tool. Give it your CI config β€” the contents of .github/workflows/.yml, your .gitlab-ci.yml, your Jenkinsfile, your .circleci/config.yml, your azure-pipelines.yml, your bitbucket-pipelines.yml and/or your .travis.yml (it auto-detects which CI system each file is) β€” and it returns a CRITICAL / VULNERABLE / RISKY / HARDENED verdict. GitHub Actions: script/expression INJECTION (attacker-controlled ${{ github.event. }} β€” issue/PR title, body, comment, branch name, commit message, label name, fork repo identity β€” into run: or actions/github-script), following taint ACROSS steps..outputs., needs..outputs., env vars, matrix values, reusable-workflow inputs.* and composite-action interiors; pull_request_target / workflow_run 'pwn requests'; reusable-workflow misuse (untrusted data over workflow_call, 'secrets: inherit'); excessive GITHUB_TOKEN permissions; unpinned third-party actions incl. transitive supply chain (tj-actions/CVE-2025-30066 class); self-hosted-runner RCE; OIDC/id-token misuse; broken if: gates. GitLab CI/CD: injection from untrusted CI variables (CI_COMMIT_REF_NAME/BRANCH/TAG, CI_MERGE_REQUEST_TITLE/DESCRIPTION/SOURCE_BRANCH_NAME, commit message/author) interpolated into script:, following taint through variables: and extends: templates AND through remote/project include: files (cross-file, the included file's sinks are resolved & analyzed); secrets / broad CI_JOB_TOKEN / id_tokens (OIDC) exposed to fork merge-request pipelines; include: from untrusted remote/foreign-project sources not pinned to a SHA; rules/only/except that let a fork MR run privileged jobs without a manual gate; and artifact/cache POISONING where an untrusted job feeds bytes a privileged downstream job executes (cross-job & cross-pipeline). Jenkins (declarative + scripted Jenkinsfile): command INJECTION from untrusted input (build params., multibranch env.CHANGE_/BRANCH_NAME, the GitHub PR-builder ghprb* vars like ghprbCommentBody, SCM commit data) interpolated into a sh/bat/powershell GString β€” following taint through pipeline/stage environment{} bindings; credential exposure (a credentials()/withCredentials secret printed with echo or baked into a shell GString, defeating log masking); Groovy evaluate()/Eval/load over untrusted input (sandbox bypass / RCE); approval-bypass (a privileged deploy/publish step reachable from a PR/comment build with no input() gate); and unsafe 'agent any' running untrusted PR code on a privileged executor. CircleCI (.circleci/config.yml): shell INJECTION from untrusted pipeline values (<< pipeline.git.branch >> / << pipeline.git.tag >> the attacker names, or a pipeline parameter set by an API/PR trigger) interpolated into a run: command; UNPINNED ORBS on a mutable version (@volatile / a bare major / dev: tag = supply-chain, the orb runs in your pipeline with your contexts); CROSS-FILE ORB INJECTION β€” an untrusted value passed to an orb-command parameter that the published orb's OWN source pipes into an internal run: sink (the orb's interior is resolved & analyzed, a flow a single-file scan can't see); fork-PR CONTEXT SECRET exposure (a job attaching an org context reachable from forked-PR builds without a type: approval gate); and missing approval gate before a privileged deploy job. Azure Pipelines (azure-pipelines.yml): macro INJECTION from untrusted predefined variables ($(Build.SourceBranch)/$(Build.SourceBranchName) the attacker names, $(System.PullRequest.SourceBranch) on fork PRs, $(Build.SourceVersionMessage) commit message) substituted into script:/bash:/pwsh: text, following taint through variables: bindings; UNTRUSTED TEMPLATES pulled from a foreign repository resource (runs in your pipeline with your secrets); CROSS-FILE TEMPLATE INJECTION β€” an untrusted value passed as a template parameter that the foreign template's OWN body pipes into an internal script:/bash: sink (the template interior is resolved & analyzed); fork variable-GROUP / secret exposure on PR-triggered pipelines; and unpinned repository resources on moving refs. Bitbucket Pipelines (bitbucket-pipelines.yml): shell INJECTION from attacker-named variables ($BITBUCKET_BRANCH / $BITBUCKET_TAG / $BITBUCKET_PR_DESTINATION_BRANCH, or a crafted commit message) expanded unquoted into a script: line in a default/pull-requests pipeline; SECURED / deployment-variable fork exposure (a PR pipeline reachable from external contributors that reads repository/deployment secrets); UNPINNED PIPES (a pipe: on :latest / a floating tag = supply-chain, the pipe runs in your step with your secrets); and ungated DEPLOYMENTS (a deployment: step with no trigger: manual reachable from PR/branch). Travis CI (.travis.yml): shell INJECTION from attacker-named TRAVIS_* variables ($TRAVIS_BRANCH / $TRAVIS_PULL_REQUEST_BRANCH / $TRAVIS_TAG / $TRAVIS_COMMIT_MESSAGE) expanded unquoted into a lifecycle hook (before_script/script/after_*); secure-env PR exposure (encrypted secure: vars present on a PR-buildable config that can leak to same-repo branch PRs / opted-in forks); and ungated DEPLOYS (a deploy: with no on: branch/condition gate that fires on any ref). HARDCODED SECRETS (all seven ecosystems): credentials committed verbatim in any CI config β€” AWS access key ids (AKIA/ASIA), GitHub tokens (ghp_/gho_/ghs_/github_pat_), GitLab/npm/Slack/Google/Stripe keys, PEM private keys, and generic high-entropy secrets assigned to secret-shaped keys β€” while correctly suppressing the SAFE indirect references (${{ secrets.X }}, $VAR, << pipeline... >>, $(Var), credentials('id'), Key Vault / vault refs) so you get the real leaks with zero false positives; evidence is redacted so the report never re-leaks the credential. OIDC CLOUD-TRUST MISCONFIGURATION (cross-domain, IaC): include your Terraform / CloudFormation / GCP workload-identity / Azure federated-credential and ci-sentinel models the CLOUD side of OIDC β€” the trust policy of the IAM role / pool / app that backs CI β€” and flags the catastrophic-but-common misconfigurations: a sub condition with a broad wildcard (repo:org/, repo:), NO sub condition at all (any workflow on the issuer can assume the role), a repo pinned but ref/environment UNpinned (any branch can assume), the bare pull_request subject (fork-reachable), or an unpinned aud. It then CORRELATES the IaC trust condition with the CI side (a workflow that mints id-token reachable from an untrusted trigger) and escalates to critical when the chain is reachable end-to-end β€” a flow no single-file CI linter catches because it spans the CI claim and the cloud trust policy. JENKINS SHARED LIBRARIES (@Library, cross-file): provide the library's vars/.groovy bodies (sharedLibYmls) and ci-sentinel taints an untrusted pipeline value (a PR title / branch / build parameter) passed to a shared-library global-var step THROUGH the library's call() interior to an internal sh/bat sink β€” the Jenkins parity of orb/template/composite-action cross-file taint, invisible when reading only the Jenkinsfile β€” plus flags @Library imports pinned to a mutable ref (a branch / default version) as supply-chain risk. The deep tier returns every finding with file:line, the full taint path and a SARIF 2.1.0 report with codeFlows, uploadable to GitHub code scanning. Use it whenever reviewing, writing or accepting CI config. Heuristic static analysis, not a guarantee.

ParametersJSON Schema
NameRequiredDescriptionDefault
deepNoWhen true, runs the PREMIUM deep audit: every finding with file:line, the full injection taint path, the transitive action supply-chain graph and concrete remediation. Requires an API key (set CI_SENTINEL_KEY in your MCP env); without one you'll get unlock instructions. The free quick verdict needs no key.
filesNoMap of filename -> content, e.g. { ".github/workflows/ci.yml": "name: CI\non: ...", ".gitlab-ci.yml": "stages: ...", "Jenkinsfile": "pipeline { ... }", ".circleci/config.yml": "version: 2.1\n...", "azure-pipelines.yml": "pool: ...", "bitbucket-pipelines.yml": "pipelines: ...", ".travis.yml": "language: ..." }. Mix GitHub Actions, GitLab CI, Jenkins, CircleCI, Azure Pipelines, Bitbucket Pipelines and Travis CI files freely β€” each is routed to the right analyzer by its name/shape. Audit a whole repo's CI at once.
sourceNoA single CI file's content (a GitHub Actions workflow, a .gitlab-ci.yml, a Jenkinsfile, a .circleci/config.yml, an azure-pipelines.yml, a bitbucket-pipelines.yml, a .travis.yml, or an IaC OIDC trust policy .tf/.json; auto-detected). Use instead of 'files' for one file.
sharedLibYmlsNoOPTIONAL (Jenkins): bodies of shared-library global vars keyed by the var NAME (the vars/<name>.groovy basename), e.g. { "deployTo": "def call(Map config){ sh \"... ${config.target}\" }" }. Lets the deep audit taint an untrusted pipeline value THROUGH a @Library step into the library's internal sh sink (cross-file). There is no public registry for shared libs, so supply the bodies here.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description fully discloses behavioral traits: it performs heuristic static analysis, requires an API key for deep audit, redacts secrets, returns a verdict and SARIF report, and lists many categories of issues. It also mentions limitations ('not a guarantee').

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is excessively long (wall of text). While it has structure (ecosystem-by-ecosystem), it contains unnecessary details that could be shortened or placed in schema descriptions. The verbosity reduces clarity for an AI agent trying to parse key points quickly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (7 ecosystems, deep audit modes, API key requirement, return format), the description is comprehensive. It explains inputs, operations, outputs (verdict and SARIF report), and even covers edge cases like cross-file analysis and secret redaction.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, yet the description adds significant value beyond the schema. For 'deep,' it explains the need for an API key. For 'files' and 'source,' it adds details about auto-detection and mixing ecosystems. For 'sharedLibYmls,' it explains cross-file taint analysis, which is not in schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool audits CI configs for security flaws, listing seven specific CI ecosystems. The verb 'Audit' and resource 'CI config' are explicit, and the tool is distinguished from its sibling 'diff_ci_security' by focusing on auditing rather than diffing.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description advises using the tool 'whenever reviewing, writing or accepting CI config,' providing clear context for its use. However, it does not explicitly state when not to use it or mention the sibling 'diff_ci_security' as an alternative for diffing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

diff_ci_securityAInspect

DIFFERENTIAL CI/CD security check for a workflow/pipeline CHANGE — the tool a PR gate needs. Give it the BEFORE and AFTER state of your CI config (e.g. a pull request that edits .github/workflows/*.yml, .gitlab-ci.yml, a Jenkinsfile, .circleci/config.yml, azure-pipelines.yml, bitbucket-pipelines.yml, .travis.yml or an IaC OIDC trust policy) and it reports exactly which security findings the change INTRODUCES, REMOVES or AGGRAVATES, plus a single verdict: INTRODUCES_RISK (block the change), REDUCES_RISK (the change hardens CI) or NEUTRAL. It runs the full 7-ecosystem deep engine on both states and reconciles the two finding sets by a LINE-INDEPENDENT identity, so an edit that merely shifts line numbers does NOT look like it introduced/removed a flaw — only a REAL security change shows up. For every introduced finding you get the file:line, the taint path and the concrete fix to undo the risk; for removed ones you see what the change fixed. This is the answer your own agent can't compute by reading the after-state alone: it has no principled BEFORE→AFTER security delta. Use it on every PR that touches CI config — wire INTRODUCES_RISK to a failing status check. Provide each side as { files: {name: yaml} } (or { source } for one file). Premium: requires an API key (set CI_SENTINEL_KEY) or pays per call via x402. Heuristic static analysis, not a guarantee.

ParametersJSON Schema
NameRequiredDescriptionDefault
afterYesThe AFTER state of the CI config (the PR / head branch). Same shape as 'before'.
beforeYesThe BEFORE state of the CI config (the base / target branch). Same shape as audit input: { files: {filename: yaml}, ... } or { source: "..." }. May also carry actionYmls/includeYmls/orbYmls/templateYmls/sharedLibYmls for cross-file resolution.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description fully discloses behavior: it runs the full engine on both states, reconciles findings using line-independent identity, produces verdicts, and provides detailed findings. It also notes it uses 'heuristic static analysis, not a guarantee' and mentions premium requirements (API key). This is thorough and transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is quite long but every sentence adds value. It is front-loaded with purpose and usage. While it could be slightly more concise, it avoids redundancy and maintains a clear logical flow.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity (2 required params with nested objects, no output schema), the description is remarkably complete. It explains input format, output verdicts, and the line-independent identity mechanism. It even describes the findings' structure (file:line, taint path, fix). All essential information is covered.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the description adds substantial meaning: it explains the before/after shape, mentions the two formats (files/source), lists additional optional fields like orbYmls and actionYmls, and clarifies how to provide each side. This goes beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it performs a 'DIFFERENTIAL CI/CD security check', comparing before/after states of CI config files. It explicitly distinguishes from the sibling tool 'audit_ci_security' which likely does single-state auditing. The verb and resource are specific, and the purpose is unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly tells when to use: 'Use it on every PR that touches CI config β€” wire INTRODUCES_RISK to a failing status check.' It contrasts with single-state analysis, explaining that this tool provides a delta that an agent cannot compute alone. This gives clear context and alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 2 tool updatesv0.1.0
    • First observedaudit_ci_security
    • First observeddiff_ci_security

TDQS

A4.5/5.0

Scored across 2 tools

Disambiguation5/5

The two tools have clearly distinct purposes: one performs a full security audit of CI configs, the other computes a differential between before and after states. No overlap or confusion possible.

Naming Consistency5/5

Both tools follow a consistent verb_ci_security pattern: audit_ci_security and diff_ci_security. The naming is uniform and predictable.

Tool Count3/5

Only 2 tools for a domain that spans 7 CI ecosystems and OIDC IaC analysis. While each tool is comprehensive, the server lacks granularity (e.g., per-ecosystem tools) which might limit agent flexibility.

Completeness4/5

The tools cover full auditing and differential analysis for all major CI/CD systems and OIDC misconfigurations. Missing are tools for fixing or managing findings, but core scanning needs are well addressed.

Maintenance

ActivityInactive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    B
    quality
    D
    maintenance
    Enables security auditing, penetration testing, and compliance validation with tools like Semgrep, Trivy, Gitleaks, and OWASP ZAP. Features strict project boundary enforcement and supports OWASP, CIS, and NIST compliance frameworks.
    7
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    A keyless, defensive code-security auditor that scans codebases for hardcoded secrets, audits dependencies for known CVEs, and checks passwords against breach data using k-anonymity.
    1
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables local security scanning and compliance gap analysis for code and text, detecting secrets, PII, and OWASP vulnerabilities, and assessing readiness across major frameworks like NCA, ISO 27001, NIST CSF, and SOC 2.
    -
  • F
    license
    Not graded
    quality
    D
    maintenance
    Audits GitHub Actions workflow files for supply-chain risks like script injection, leaked tokens, unpinned actions, and broad permissions.
    -