Skip to content

Escape HTML output in builtin /flags service - #3529

Open
wwbmmm wants to merge 1 commit into
apache:masterfrom
wwbmmm:oncall/req-20260906-131706
Open

Escape HTML output in builtin /flags service#3529
wwbmmm wants to merge 1 commit into
apache:masterfrom
wwbmmm:oncall/req-20260906-131706

Conversation

@wwbmmm

@wwbmmm wwbmmm commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Problem Summary:
The builtin /flags service wrote the gflag name and value into the HTML page without escaping in two places: the ?setvalue= confirmation message and the ?setvalue&withform form page (set_value_page). Unlike the flag list page, which already escapes values with HtmlReplace, these two sinks rendered the raw value, so a value containing HTML metacharacters was injected into the page markup.

What is changed and the side effects?

Changed:

  • Escape the flag name and current_value in set_value_page with WebEscape.
  • Escape the flag name and the new value in the ?setvalue= confirmation message with WebEscape.

Side effects:

  • Performance effects: none, only affects HTML rendering of the /flags pages.

  • Breaking backward compatibility: none. Plain-text output (non-browser requests) is unchanged.


Check List:

  • Added BuiltinServiceTest.flags_escaping covering the reflected (?setvalue=<payload>) and stored (?setvalue&withform) HTML rendering plus the unchanged plain-text output; the test uses a reloadable string gflag and restores its value afterwards.
  • Full test/brpc_builtin_service_unittest passes (20 tests).

🤖 This PR was automatically created by brpc-oncall

The ?setvalue= confirmation message and the ?setvalue&withform page
wrote the gflag name/value into the html page without escaping, unlike
the flag list page which already escapes values with HtmlReplace.
Escape them with WebEscape like rpcz_service does. Plain text output
is unchanged.
@wwbmmm
wwbmmm marked this pull request as ready for review September 6, 2026 14:27
@wwbmmm
wwbmmm requested a lite review from Copilot September 6, 2026 14:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new test mutates a global gflag and should use RAII (e.g., GFLAGS_NAMESPACE::FlagSaver) to guarantee flag restoration even on early ASSERT_* exits, preventing cross-test contamination.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR hardens the builtin /flags HTML pages against HTML injection by escaping user-controlled gflag names/values at two previously unescaped sinks, and adds a regression test to validate both reflected and stored rendering behavior.

Changes:

  • Escape gflag name/value in the ?setvalue&withform HTML form page (set_value_page) using WebEscape.
  • Escape gflag name/value in the HTML confirmation message for ?setvalue=... updates.
  • Add BuiltinServiceTest.flags_escaping to cover reflected/stored HTML escaping and unchanged plain-text output.
File summaries
File Description
src/brpc/builtin/flags_service.cpp Escapes gflag name/value when rendering the HTML set-value form and HTML confirmation output.
test/brpc_builtin_service_unittest.cpp Adds a reloadable string flag + a new test that exercises both HTML sinks and verifies plain-text output remains unescaped.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +704 to +708
const std::string payload = "<svg onload=alert(1)>&\"'";
const std::string escaped = brpc::WebEscape(payload);
std::string saved_value;
ASSERT_TRUE(GFLAGS_NAMESPACE::GetCommandLineOption(
"reloadable_string_flag_for_ut", &saved_value));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants