security: escapeJavaScript is insufficient — XSS risk in SetAttribute #12

Closed
opened 2026-02-14 16:06:28 +00:00 by Claude · 2 comments
Collaborator

Parent: #2

Description

In node.go:107-113, escapeJavaScript() only escapes \ and ' characters:

func escapeJavaScript(s string) string {
    return strings.Replace(strings.Replace(s, "\\", "\\\\", -1), "'", "\\'", -1)
}

func (n node) SetAttribute(name, value string) error {
    _, err := n.locator.Evaluate(
        fmt.Sprintf(`(element) => element.setAttribute('%s', '%s');`,
            escapeJavaScript(name), escapeJavaScript(value)), nil)
    return err
}

This is missing escapes for:

  • Newlines (\n, \r) — can break the string literal
  • Null bytes (\0) — can terminate strings early
  • Backticks — could break out of template literals in some contexts
  • </script> sequences — could break out of script tags
  • Double quotes (") — while not used in the current template, defensive escaping is good practice

If user-controlled input flows through SetAttribute, this could allow JavaScript injection in the browser context.

Fix

Replace with a proper JavaScript string escaper:

func escapeJavaScript(s string) string {
    r := strings.NewReplacer(
        "\\", "\\\\",
        "'", "\\'",
        "\"", "\\\"",
        "\n", "\\n",
        "\r", "\\r",
        "\t", "\\t",
        "\x00", "\\x00",
        "</", "<\\/",
    )
    return r.Replace(s)
}

Or better yet, pass name and value as Playwright Evaluate arguments instead of string interpolation:

_, err := n.locator.Evaluate(
    `([name, value]) => element.setAttribute(name, value)`,
    []string{name, value})
**Parent:** #2 ## Description In `node.go:107-113`, `escapeJavaScript()` only escapes `\` and `'` characters: ```go func escapeJavaScript(s string) string { return strings.Replace(strings.Replace(s, "\\", "\\\\", -1), "'", "\\'", -1) } func (n node) SetAttribute(name, value string) error { _, err := n.locator.Evaluate( fmt.Sprintf(`(element) => element.setAttribute('%s', '%s');`, escapeJavaScript(name), escapeJavaScript(value)), nil) return err } ``` This is missing escapes for: - **Newlines** (`\n`, `\r`) — can break the string literal - **Null bytes** (`\0`) — can terminate strings early - **Backticks** — could break out of template literals in some contexts - **`</script>`** sequences — could break out of script tags - **Double quotes** (`"`) — while not used in the current template, defensive escaping is good practice If user-controlled input flows through `SetAttribute`, this could allow JavaScript injection in the browser context. ## Fix Replace with a proper JavaScript string escaper: ```go func escapeJavaScript(s string) string { r := strings.NewReplacer( "\\", "\\\\", "'", "\\'", "\"", "\\\"", "\n", "\\n", "\r", "\\r", "\t", "\\t", "\x00", "\\x00", "</", "<\\/", ) return r.Replace(s) } ``` Or better yet, pass `name` and `value` as Playwright `Evaluate` arguments instead of string interpolation: ```go _, err := n.locator.Evaluate( `([name, value]) => element.setAttribute(name, value)`, []string{name, value}) ```
Claude added the priority/criticalsecuritytype/task labels 2026-02-14 16:07:31 +00:00
Author
Collaborator

Starting work on this. Plan: replace string interpolation in SetAttribute with Playwright's Evaluate argument passing to eliminate the injection surface entirely. Will remove the vulnerable escapeJavaScript function and update tests.

Starting work on this. Plan: replace string interpolation in `SetAttribute` with Playwright's `Evaluate` argument passing to eliminate the injection surface entirely. Will remove the vulnerable `escapeJavaScript` function and update tests.
Author
Collaborator

Work finished. PR: #32

Replaced string interpolation with Playwright's Evaluate argument passing, eliminating the injection surface entirely. Removed the vulnerable escapeJavaScript helper.

Work finished. PR: #32 Replaced string interpolation with Playwright's `Evaluate` argument passing, eliminating the injection surface entirely. Removed the vulnerable `escapeJavaScript` helper.
Sign in to join this conversation.