A blog post may look like plain text to the person submitting it but contain JavaScript that runs when someone else opens the page. This is a cross-site scripting (XSS) attack: injected script is stored as user content, then executed in another user’s browser. section 11.10
A comment with a hidden script
A user enters ordinary text around `<script>malicious_function()</script>`. If the application saves that text and displays it in a post without preventing the script from running, a later visitor’s browser may execute it. section 11.10
Treat user-entered post and comment text differently from values supplied by the application. In a Jinja2 template, `| safe` prevents Jinja2 from translating potentially dangerous symbols. It is used for an application-supplied JSON value in a JavaScript block; applying the same treatment to user-supplied data could expose an XSS risk. section 6.4.4
For user-entered content, sanitize it before saving it. A form filter calls `bleach.clean()` on non-`None` input; fields such as a post’s `PageDownField` run that filter when the form is submitted, before the application reads the field data. The practical distinction is where the value came from: application-generated data in a template is not the same as text a visitor can submit. section 11.10 section 6.4.4
content = PageDownField(
"Content",
validators=[DataRequired()],
filters=(remove_html_and_script_tags,),
render_kw={"placeholder": " ", "tabindex": 2}
)
The post content field attaches the sanitizing function through its `filters` parameter, keeping the check on the form-input path. section 11.10


