Skip to content

fix(kubescape-bridge): contain scanner severity in a code span rather than enumerating metacharacters #2928

Closed

Description

@devantler

🤖 Generated by the Agentic Engineer

sanitizeForIssue neutralizes * but not _ or ~~, so the fix landed for
"Neutralize Markdown in scanner-derived severity" is incomplete against its own stated goal.

Evidence

renderBody writes exactly one scanner-derived field into a live-Markdown context:

fmt.Fprintf(&b, "**Severity:** %s\n", boundField(t.Severity))   // bare — Markdown is live
b.WriteString("- `" + boundField(c) + "`\n")                    // inside a code span — inert

Running the replacer from issues.go verbatim over the Markdown/HTML metacharacter set:

NEUTRALIZED : @ # < [ * `
PASSES THRU : > ] _ ~ | & ! = - +

  **Severity:** *High*     -> "**Severity:** *<ZWSP>High*<ZWSP>"   (neutralized)
  **Severity:** _High_     -> "**Severity:** _High_"               (renders as emphasis)
  **Severity:** ~~High~~   -> "**Severity:** ~~High~~"             (renders as strikethrough)

* and _ are the same Markdown construct; only one of them was covered.

Impact — deliberately graded LOW

I checked every pass-through for a side-effecting vector and found none:

Char Why it is not reachable here
! image syntax needs ![, and [ is neutralized
> blockquote needs line start; \n/\r are already stripped to spaces
- = setext heading needs line start; same reason
& an entity renders as a character, not as markup
` `

So the reachable effect is cosmetic emphasis only — no mention, no cross-link, no HTML
structure. This is a completeness gap, not a vulnerability, which is why it is filed as a Bug
rather than as Security.

The real cost: the character set is enumerated by discovery

Across 8 review rounds on #2917 the replacer grew @/# → < → *, one round at a time,
each found adversarially rather than derived. _ is simply the next one. The set has no
closure argument, so this recurs.

Smallest useful change

Render Severity through the containment the component list already uses — a code span:

fmt.Fprintf(&b, "**Severity:** `%s`\n", boundField(t.Severity))

A code span is escapable only by a backtick, and sanitizeForIssue already maps ` → '.
That makes every metacharacter inert in one move, including ones not yet enumerated. Verified,
with the control:

in="_High_"     span="**Severity:** `_High_`"     span_escapable=false
in="~~High~~"   span="**Severity:** `~~High~~`"   span_escapable=false
in="x`+live`y"  span="**Severity:** `x'+live'y`"  span_escapable=false

CONTROL (backtick NOT neutralized): "x`+live`y" span_escapable=true   <-- control flips

Acceptance criteria

  1. A test asserts _, ~~, | and & in t.Severity cannot produce live markup — RED before
    the change, GREEN after.
  2. An ablation removes the backtick→' mapping and the containment test FAILS, proving the
    guarantee rests on that mapping and the test is not vacuous.
  3. The anti-churn guarantee is preserved: identical input renders identical bytes.
  4. entrySurface still parses the **Surface:** line it round-trips (that line is untouched).

Size: XS — one format string, one test, one ablation.

Part of #2854. Follow-up from #2917; deliberately not folded into it, because that PR is
pentad-clear at head after 8 review rounds and every push restarts a metered review loop.

Activity

  1. added theissue type on Aug 3, 2026
  2. moved this to 📥 Backlog in 🌊 Project Boardon Aug 3, 2026
  3. coderabbitai commented on Aug 3, 2026

    @coderabbitai
    Contributor
    🔗 Related PRs

    #2479 - fix(kubescape): anchor the remaining literal CSE name matchers [merged]
    #2776 - fix(lint): scope the lint gate to the paths it actually governs [merged]
    #2830 - feat(ci): publish Kubescape posture findings to Code Scanning [merged]
    #2847 - fix(ci): report what the Kubescape scan actually found [merged]
    #2876 - feat(security): derive themed, deduped backlog entries from live Kubescape findings [merged]


    📝 Issue Planner

    Check the box below or use the @coderabbitai plan command to generate an implementation plan and prompts that you can use with your favorite coding assistant.

    • Create Plan

    🧪 Issue enrichment is currently in open beta.

    You can configure auto-planning by selecting labels in the issue_enrichment configuration.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

  4. self-assigned this
    on Sep 21, 2026
  5. moved this from 📥 Backlog to 👀 In Review in 🌊 Project Boardon Sep 21, 2026
  6. moved this from 👀 In Review to ✅ Done in 🌊 Project Boardon Sep 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Fields

Priority

None yet

Effort

None yet

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions