go-gitea/gitea · critical
Markup sanitizer rule regexp must start with ^ and end with
Error message
Markup sanitizer rule regexp must start with ^ and end with $ to be strict
What it means
A start-time panic in Gitea's custom markup sanitizer. When app.ini defines [markup.sanitizer.*] rules with both ELEMENT and REGEXP, the code enforces that the regexp is anchored: it must begin with ^ and end with $. This strictness stops attacker-supplied markup from smuggling partial matches past the allow-list (e.g., a regexp like https?://evil\.com matching inside a longer attribute value), so a non-anchored rule aborts startup deliberately.
Source
Thrown at modules/markup/sanitizer_custom.go:23
import (
"regexp"
"strings"
"gitea.dev/modules/setting"
"github.com/microcosm-cc/bluemonday"
)
func (st *Sanitizer) addSanitizerRules(policy *bluemonday.Policy, rules []setting.MarkupSanitizerRule) {
for _, rule := range rules {
if rule.AllowDataURIImages {
policy.AllowDataURIImages()
}
if rule.Element != "" {
if rule.Regexp != "" {
if !strings.HasPrefix(rule.Regexp, "^") || !strings.HasSuffix(rule.Regexp, "$") {
panic("Markup sanitizer rule regexp must start with ^ and end with $ to be strict")
}
policy.AllowAttrs(rule.AllowAttr).Matching(regexp.MustCompile(rule.Regexp)).OnElements(rule.Element)
} else {
policy.AllowAttrs(rule.AllowAttr).OnElements(rule.Element)
}
}
}
}
View on GitHub (pinned to 43ace7cc8a)
Solutions
- Edit app.ini and anchor every sanitizer REGEXP: wrap the pattern as ^...$ (e.g. REGEXP = ^https?://example\.com/.*$)
- Restart Gitea and confirm startup succeeds
- Validate all other [markup.sanitizer.*] sections for the same problem in one pass
- After it boots, test the sanitizer with a crafted issue/comment containing the element to confirm the rule matches as intended
Example fix
; before [markup.sanitizer.example] ELEMENT = a ALLOW_ATTR = href REGEXP = https?://example\.com/.* ; after [markup.sanitizer.example] ELEMENT = a ALLOW_ATTR = href REGEXP = ^https?://example\.com/.*$
Defensive patterns
Strategy: validation
Validate before calling
// Validate app.ini sanitizer rules before boot (config linter / pre-flight check)
func validateSanitizerRegexp(rules []setting.MarkupSanitizerRule) error {
for _, r := range rules {
if r.Element != "" && r.Regexp != "" {
if !strings.HasPrefix(r.Regexp, "^") || !strings.HasSuffix(r.Regexp, "$") {
return fmt.Errorf("markup.sanitizer rule for %q: REGEXP %q must start with ^ and end with $", r.Element, r.Regexp)
}
if _, err := regexp.Compile(r.Regexp); err != nil {
return fmt.Errorf("markup.sanitizer rule for %q: invalid REGEXP: %w", r.Element, err)
}
}
return nil
} Type guard
// Go: guard before applying a rule
func isStrictRegexp(s string) bool {
return strings.HasPrefix(s, "^") && strings.HasSuffix(s, "$")
} Try / catch
// Panics happen at process start; catch them in the supervisor/deployment, not in code: // run `gitea doctor` / a config-dry-run in the container entrypoint before exec'ing the server // so a bad app.ini fails fast with a clear message instead of a crash loop.
Prevention
- Always author sanitizer regexps fully anchored: ^pattern$ — write the anchors first, then the pattern
- Lint app.ini in CI or with `gitea doctor` after every markup.sanitizer edit, before restarting production
- Trim surrounding whitespace in REGEXP values; a space after $ makes the check fail mysteriously
- Test the rule with both a matching and a non-matching attribute value after startup
When it happens
Trigger: Any [markup.sanitizer.<name>] section in app.ini with ELEMENT set and a REGEXP that does not start with ^ or does not end with $: e.g. REGEXP = ^https?:// (missing trailing $), REGEXP = .* (no anchors), or trailing whitespace/newline after the $ in the quoted value.
Common situations: Copying a sanitizer example from an outdated blog/docs where anchors were not required; upgrading Gitea to a version that introduced the anchor enforcement against configs that previously worked; hand-editing app.ini and introducing a typo or missing anchor; trailing spaces after $ inside the value.
Related errors
AI-assisted analysis of go-gitea/gitea@43ace7cc8a (2026-08-15).
Data as JSON: /api/errors/094ae3763d2f8780.
Report an issue: GitHub.