Remove raw JavaScript support and tighten CSP defaults - #337
Merged
Merged
Conversation
…d the fences the gates skipped Bugs found by reading the site's scripts and theme against the built pages: - build-site: the "On this page" outline escaped the heading text a second time, so "Build & Test" read "Build & Test" and a heading with quotes or angle brackets spelt out its entities. The text out of the rendered heading is HTML already and is written back as it is. - pages.mjs: heading anchors in the search index were a plain slug, not VitePress's - a heading starting with a digit, one carrying an arrow or a long dash, and the second heading of one name on a page all opened the page at the top. 93 of 737 heading links were dead. slugify is now the copy of @mdit-vue/shared's, with markdown-it-anchor's -1 suffix, and test/search.test.mjs pins the three shapes. - build-site: the 404 page suggested /docs/<section>.html for a section's index page, which the build never writes; the suggestion keeps its `index` now. - list-runnable, check-examples, check-api-names: a fence with an info string (```abap edit on the front door, ```abap [ABAP] in the quickstart, ```abap [lcl_help]) was invisible to all three, so the most-copied example on the site was never compiled and the runnable count read 63 against check:playground's 64. The regexes accept the info string; check:examples now compiles 70 classes, runnable lists 64. - SiteNav.vue: the Playground item bound an href that was declared nowhere, and leave( ) sent every non-docs item to the catalogue - a press on Playground opened Samples in the VitePress build. It has its ref, is lifted like the other two, and leave( ) branches on the site. - playground.js: a failed load of the embed loader was cached for the life of the page; the promise is forgotten on error so the next press retries. - playground.mjs: the Run-button rules did not see CLASS-METHODS as a declaration (a class with one unimplemented got a button) and did not know popover_display as output. - build-site: a Shiki line with a second class (highlighted, diff) fell out of the rebuilt listing; and a build with disagreeing release numbers now fails instead of printing "Version null" in every bar. - README: the API gates judge against main, not the release the site names, as AGENTS.md has said since the pin was cut; the Run-button count is the measured one. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBw7XcLuTa94iCUYZEtuh5
…e name is -1 `## EML` under `# EML` is `eml-1` in the built page, because markdown-it-anchor counts every heading. headings( ) now counts the title too and still indexes only the second and third level; the test says so with the real shape. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBw7XcLuTa94iCUYZEtuh5
…and the repo's own words brought up to date - docs.css: the print block set a white page and kept the dark palette - the site switches schemes by attribute, which a browser's print emulation does not touch - so a reader who chose dark printed light grey on white. The tokens go back to light under @media print. The same block hid a `.run-panel` nothing writes; it hides the Run button, the running frame, its bar and the fold button now. The outline's two media queries both matched at exactly 1100px. - style.css (the VitePress second opinion): the focus-ring selector list ended in a comma and ran into the line-counter rule, so nothing focused had a ring and everything focused had `counter-reset: line`. - config.mjs: apple-touch-icon pointed at the .ico; the PNG the static build writes exists. - build-site: the drawer's checkbox carries an accessible name once its label's text is hidden at desk width. - index.md: rel="noopener" on the project's own links, as build-site says. - README, SECURITY, CONTRIBUTING, package.json: fifteen gates, not eight; the README's list now names all fifteen; the first two sections of the bar are this site, not the middle two; the site is written by scripts/build-site.mjs, not VitePress; and SECURITY says what the build fetches and runs from the sibling deployment, which a security reader should know. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBw7XcLuTa94iCUYZEtuh5
…), and a dozen sentences match the framework again
Read against z2ui5_if_client on main and the framework's source:
- Frontend, Deprecations, WebSocket: `follow_up_action( )` no longer runs a
raw JavaScript expression - the client class says so in as many words
("there is no code form: a raw JavaScript val is not run") - yet the
Frontend page carried a hundred lines on how to, the deprecations table
named "a raw expression" as the replacement for three removed things, and
the WebSocket page opened its socket with one. The section says what
replaced the form (control_global, control_by_id, hash_back, a custom
control in z2ui5_ccc), the table rows point there, and the WebSocket page
names the frontend's own cc/Websocket, which its sample uses.
- Frontend: `ICON_POOL` is on the control_global whitelist; the method is
`addCustomCurrencies` and it merges rather than adding one code;
`setNextStep` is a WizardStep's method, so the example addresses the step.
- Troubleshooting: the type-coercion section said `abap_bool` arrives as
"X" and a CheckBox needs a formatter - the Formatter and Binding pages,
and the framework, say the boolean types travel as JSON true/false and the
trap is a flag typed `c LENGTH 1`. The event-name section pointed at
`cs_event-*` for the reader's own event names, which are frontend actions.
- Popup: `NEW z2ui5_cl_sample_confirm( mv_question = … )` on a class with no
constructor; the attribute is set after NEW, as the other pages do.
- Walkthrough step 3 and the cheat sheet said the check_* methods are
exclusive; `check_on_init( )` implies `check_on_navigated( )`, which is why
init goes first. Step 7 said one step was left with three to go.
- Value Help: an `i_multiselect` / `ls_res-table` sentence left over from a
removed built-in popup, and old typed-builder names for the suggestion
aggregation. Demo Output named `_cc_plain_xml`, a method of the frozen
builder, for what the code does with core:HTML.
- Themes: the Belize rows and the user exit example - removed in UI5 1.136,
as the View page already says. Insight 22: the framework's CSRF gate is
a check, not a token. Insight 12: `custom_js` exists only in the frozen
package. Renaming: the exit lookup's literal is `Z2UI5_IF_UI5_EXIT`, with
a fallback beside it - not the two the page named.
- i18n: a text symbol goes on a single-quoted literal, as the sample has it.
Barcode: SAPUI5, not "the UI5 framework". About: ten runnable steps.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RBw7XcLuTa94iCUYZEtuh5
…setup pages match the code again - Security: the default policy carried no jsDelivr and no cdnjs, no 'unsafe-eval' and no 'unsafe-inline' for scripts for a while - the page showed the old tag, called 'unsafe-eval' part of the default, and told the reader to remove it by pasting a whole tag that re-added the CDN hosts and 'unsafe-inline' to default-src: a reader who followed the hardening section ended up weaker than the default. The page now shows the shipped tag, explains the explicit script-src/style-src split and the script hash, edits a directive with REPLACE instead of replacing the tag, and keeps one section for the 1.71 to 1.82 popup case that switches 'unsafe-eval' on. The header table no longer lists cache-control among the exit's defaults (the handler decides caching per verb), and the CSRF sentence names the X-Forwarded-Host precedence and its switch. UI5 bootstrapping and the troubleshooting page linked the old section; they say the new thing. - Bootstrap attributes: a row in t_add_config cannot override an attribute the framework writes first - a browser keeps the first of two - so the page stops promising that and drops frameOptions from its example. - Developer Tools (debugging, hello world): the six tabs and the footer as they are. Hello world quotes the start page's actual error text. - Renaming: src/02 holds five objects; the workflow is build-rename; custom-controls-customer lives in abap2UI5-addons. abaplint page: the rename config is rename.jsonc. Frontend extensibility: two ui5 yaml files. - setup / user exits: set_config_http_get runs once more per response for its security headers. Performance: public means part of the model, not "not serialized". VS Code: the distribution setting has no default. S/4 Public Cloud: `cloud` is the classic runtime, `cloud_v2` the legacy-free preview. Walkthrough step 11: the mobile_start page is about SAP Mobile Start, not the home screen. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBw7XcLuTa94iCUYZEtuh5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This change removes the deprecated raw JavaScript feature from
follow_up_action()and significantly hardens the default Content Security Policy.Summary
The raw JavaScript injection pattern — where backends could send arbitrary
<script>tags to execute in the browser — has been removed entirely. This was a self-inflicted XSS vector that bypassed UI5's output encoding and broke strict Content Security Policies. All use cases now have safer alternatives through built-in frontend events or custom controls.The default CSP has been tightened to remove
'unsafe-eval'and'unsafe-inline'for scripts, with the page's single inline script now allowed only by its SHA-256 hash. This closes a major attack surface while maintaining compatibility with modern UI5 releases.Key Changes
follow_up_action()no longer accepts arbitrary JavaScript expressions. Unknown event names are silently ignored rather than executed.control_global,control_by_id,hash_back, or custom controls instead.'unsafe-eval'and'unsafe-inline'from script-srcscript-srcandstyle-srcinto explicit directives (no longer relying ondefault-srcfallback)style-srcretains'unsafe-inline'because UI5 renders style attributescs_event-hash_back, custom controls inz2ui5_ccc)STEP1instead ofwiz)ICON_POOLto global objects: Extended the whitelist of callable global objects incontrol_globalImplementation Details
eval()). Only UI5 1.71–1.82 popups may need'unsafe-eval're-enabled via the user exit.z2ui5_ccc), with defined interfaces and reviewable code.slugifyfunction, fixing 93 previously broken heading links in the documentation index.https://claude.ai/code/session_01RBw7XcLuTa94iCUYZEtuh5