Mercurial > p > roundup > code
view share/roundup/templates/devel/html/page.html @ 8365:4ac0bbb3e440
bug(security): CVE-2025-53865 - XSS bug
Extensive fixes in devel, responsive templates known to be
exploitable.
Similar constructs in classic and minimal templates not known
to be exploitable, but changed anyway.
doc/upgrading.txt:
Reformat to 66 characters.
Update with assigned CVE number.
Add section on fixing tal:replace with unsafe data.
Document analysis and assumptions in comment in file.
doc/security.txt:
Update with CVE number.
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Fri, 11 Jul 2025 19:30:27 -0400 |
| parents | 2bf0c4e7795e |
| children | 15a92b0a9b79 |
line wrap: on
line source
<tal:block metal:define-macro="frame"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title metal:define-slot="head_title">title goes here</title> <link rel="stylesheet" type="text/css" href="@@file/style.css" /> <meta http-equiv="Content-Type" tal:attributes="content string:text/html;; charset=${request/client/charset}" /> <script tal:replace="structure request/base_javascript"></script> <metal:x define-slot="more-javascript" /> </head> <body tal:attributes="class request/classname" tal:define="kw_create python:request.user.hasPermission('Create', 'keyword'); bug_columns string:id,activity,title,creator,status; bug_columns_showall string:id,activity,title,creator,assignee,status; bug_status_notclosed string:-1,1,2,4; task_columns string:id,activity,title,creator,status; task_columns_showall string:id,activity,title,creator,assignee,status; task_status_notclosed string:-1,1,2,4; milestone_columns string:id,activity,title,creator,status; milestone_columns_showall string:id,activity,title,creator,assignee,status; milestone_status_notclosed string:-1,1,2,4;"> <div class="header"> <h1><a href="/">Roundup Demo Tracker</a></h1> <div id="searchbox"> <form name="searchform" method="get" action="bug" id="searchform"> <div id="search"> <input type="hidden" name="@columns" tal:attributes="value bug_columns_showall"/> <input type="hidden" name="@sort" value="-activity" /> <input type="hidden" name="@group" value="priority" /> <input type="hidden" name="@filter" value="status"/> <input type="hidden" name="status" tal:attributes="value bug_status_notclosed"/> <input class="input-text" id="search-text" name="@search_text" size="10" /> <input type="submit" id="submit" value="search in open bugs" name="submit" class="input-button"/> </div> </form> </div> <!-- searchbox --> </div> <!-- header --> <div class="navigation"> <div class="menu"> <ul> <li class="current"><a href="/" i18n:translate="">Bugs</a> <ul tal:condition="python:request.user.hasPermission('View', 'bug')"> <li tal:condition="python:request.user.hasPermission('Create', 'bug')"> <a href="bug?@template=item" i18n:translate="">Create New</a> </li> <li> <a href="#" tal:attributes="href python:request.indexargs_url('bug', { '@sort': '-activity', '@group': 'priority', '@filter': 'status', '@columns': bug_columns_showall, '@search_text': '', 'status': bug_status_notclosed, '@dispname': i18n.gettext('Show All'), '@startwith': 0, })" i18n:translate="">Show Open</a> </li> <li><a href="#" tal:attributes="href python:request.indexargs_url('bug', { '@sort': '-activity', '@group': 'priority', '@filter': 'status,assignee', '@columns': bug_columns, '@search_text': '', 'status': bug_status_notclosed, 'assignee': '-1', '@dispname': i18n.gettext('Show Unassigned'), '@startwith': 0, })" i18n:translate="">Show Unassigned</a> </li> <li> <a href="bug?@template=search&status=1" i18n:translate="">Search</a> </li> <li> <form method="post" action="#"> <input type="submit" class="form-small" value="Show bug:" i18n:attributes="value"/> <input class="form-small" size="4" type="text" name="@number"/> <input type="hidden" name="@type" value="bug"/> <input name="@csrf" type="hidden" tal:attributes="value python:utils.anti_csrf_nonce()"> <input type="hidden" name="@action" value="show"/> </form> </li> </ul> </li> <li class="current"><a href="/" i18n:translate="">Tasks</a> <ul tal:condition="python:request.user.hasPermission('View', 'task')"> <li tal:condition="python:request.user.hasPermission('Create', 'task')"> <a href="task?@template=item" i18n:translate="">Create New</a> </li> <li> <a href="#" tal:attributes="href python:request.indexargs_url('task', { '@sort': '-activity', '@group': 'priority', '@filter': 'status', '@columns': task_columns_showall, '@search_text': '', 'status': task_status_notclosed, '@dispname': i18n.gettext('Show All'), '@startwith': 0, })" i18n:translate="">Show Open</a> </li> <li> <a href="#" tal:attributes="href python:request.indexargs_url('task', { '@sort': '-activity', '@group': 'priority', '@filter': 'status,assignee', '@columns': task_columns, '@search_text': '', 'status': task_status_notclosed, 'assignee': '-1', '@dispname': i18n.gettext('Show Unassigned'), '@startwith': 0, })" i18n:translate="">Show Unassigned</a> </li> <li> <a href="task?@template=search&status=1" i18n:translate="">Search</a> </li> <li> <form method="post" action="#"> <input type="submit" class="form-small" value="Show task:" i18n:attributes="value"/> <input class="form-small" size="4" type="text" name="@number"/> <input type="hidden" name="@type" value="task"/> <input name="@csrf" type="hidden" tal:attributes="value python:utils.anti_csrf_nonce()"> <input type="hidden" name="@action" value="show"/> </form> </li> </ul> </li> <li class="current"><a href="milestone" i18n:translate="">Milestones</a> <ul tal:condition="python:request.user.hasPermission('View', 'milestone')"> <li tal:condition="python:request.user.hasPermission('Create', 'milestone')"> <a href="milestone?@template=item" i18n:translate="">Create New</a> </li> <li> <a href="#" tal:attributes="href python:request.indexargs_url('milestone', { '@filter': 'status', 'status': milestone_status_notclosed, '@dispname': i18n.gettext('Show Open'), '@startwith': 0, '@group': 'status', })" i18n:translate="">Show Open</a> </li> </ul> </li> </ul> <ul class="user"> <li tal:condition="python:request.user.username=='anonymous'" class="submenu"> <b i18n:translate="">User</b> <form method="post" tal:attributes="action request/base"> <ul> <li> <tal:span i18n:translate="">Login</tal:span><br/> <input size="10" required name="__login_name"/><br/> <input size="10" spellcheck="false" type="password" required name="__login_password"/><br/> <input name="@csrf" type="hidden" tal:attributes="value python:utils.anti_csrf_nonce()"> <input type="hidden" name="@action" value="Login"/> <input type="checkbox" name="remember" id="remember"/> <label for="remember" i18n:translate="">Remember me?</label><br/> <input class="form-small" type="submit" value="Login" i18n:attributes="value"/><br/> <input type="hidden" name="__came_from" tal:condition="exists:request/env/QUERY_STRING" tal:attributes="value string:${request/base}${request/env/PATH_INFO}?${request/env/QUERY_STRING}"/> <input type="hidden" name="__came_from" tal:condition="not:exists:request/env/QUERY_STRING" tal:attributes="value string:${request/base}${request/env/PATH_INFO}"/> <span tal:replace="structure request/indexargs_form" /> </li> <li> <a href="user?@template=register" tal:condition="python:request.user.hasPermission('Register', 'user')" i18n:translate="">Register</a> </li> <li> <a href="user?@template=forgotten" i18n:translate="">Lost your login?</a> </li> </ul> </form> </li> <li tal:condition="python:request.user.username != 'anonymous'" class="submenu"> <p class="label"><b tal:replace="python:request.user.username.plain(escape=1)">username</b></p> <ul> <li> <a href="#" tal:attributes="href python:request.indexargs_url('bug', { '@sort': '-activity', '@group': 'priority', '@filter': 'status,assignee', '@columns': bug_columns, '@search_text': '', 'status': bug_status_notclosed, 'assignee': request.user.id, '@dispname': i18n.gettext('Bugs assigned to you'), '@startwith': 0})" i18n:translate="">Bugs assigned to you</a> </li> <li> <a tal:attributes="href string:user${request/user/id}" i18n:translate="">Your Details</a> </li> <li> <a tal:attributes="href python:request.indexargs_url('', {'@action':'logout'})" i18n:translate="">Logout</a> </li> <li class="" tal:condition="python:request.user.hasPermission('View', 'query')"> <span i18n:translate=""><b>Your Queries</b> (<a class="nomargin" href="query?@template=edit">edit</a>)</span><br/> <ul tal:repeat="qs request/user/queries"> <li> <a tal:attributes="href string:${qs/klass}?${qs/url}&@dispname=${qs/name/url_quote}" tal:content="qs/name">link</a> </li> </ul> </li> <li class="" tal:condition="python:request.user.hasPermission('View', 'user')"> <b i18n:translate="">Administration</b> <ul> <li tal:condition="python:request.user.hasPermission('Edit', None)"> <a href="home?@template=classlist" i18n:translate="">Class List</a> </li> <li tal:condition="python:request.user.hasPermission('View', 'user') or request.user.hasPermission('Edit', 'user')"> <a href="user?@sort=username" i18n:translate="">User List</a> </li> <li tal:condition="python:request.user.hasPermission('Create', 'user')"> <a href="user?@template=item" i18n:translate="">Add User</a> </li> <li tal:condition="python:request.user.hasPermission('Edit', 'keyword')"> <a href="keyword" i18n:translate="">Edit Keywords</a> </li> </ul> </li> </ul> </li> </ul> <!-- user --> </div> <!-- menu --> </div> <!-- navigation --> <div class="content"> <h1 id="breadcrumb"><span metal:define-slot="body_title">body title</span></h1> <p tal:condition="options/error_message | nothing" class="error-message" tal:repeat="m options/error_message" tal:content="structure string:$m <br/ > " /> <p tal:condition="options/ok_message | nothing" class="ok-message"> <span tal:repeat="m options/ok_message" tal:content="structure string:$m <br/ > " /> <a class="form-small" tal:attributes="href request/current_url" i18n:translate="">clear this message</a> </p> <tal:block metal:define-slot="content">Page content goes here</tal:block> </div> <!-- content --> <div class="footer"> <!-- Created: Wed Jan 14 11:55:38 EST 2009 --> <!-- hhmts start --> Last modified: Wed Jun 3 00:02:37 EDT 2009 <!-- hhmts end --> </div> <!-- footer --> <pre tal:condition="request/form/deissue | nothing" tal:content="request"></pre> <script type="text/javascript" src='@@file/datecopy.min.js'></script> </body> </html> </tal:block> <!-- The following macros are intended to be used in search pages. The invoking context must define a "name" variable which names the property being searched. See issue.search.html in the classic template for examples. --> <!-- creates a th and a label: --> <th metal:define-macro="th_label" tal:define="required required | python:[]" tal:attributes="class python:(name in required) and 'required' or nothing"> <label tal:attributes="for name" tal:content="label" i18n:translate="">text</label> <metal:x define-slot="behind_the_label" /> </th> <td metal:define-macro="search_input"> <input tal:attributes="value python:request.form.getvalue(name) or nothing; name name; id name"/> </td> <td metal:define-macro="search_date"> <input tal:attributes="value python:request.form.getvalue(name) or nothing; name name; id name"/> <a class="classhelp" tal:attributes="href python:'''javascript:help_window('task?@template=calendar&property=%s&form=itemSynopsis', 300, 200)'''%name">(cal)</a> </td> <td metal:define-macro="search_popup"> <!-- context needs to specify the popup "columns" as a comma-separated string (eg. "id,title" or "id,name,description") as well as name --> <input tal:attributes="value python:request.form.getvalue(name) or nothing; name name; id name"/> <span tal:replace="structure python:db.task.classhelp(columns, property=name)" /> </td> <td metal:define-macro="search_select"> <select tal:attributes="name name; id name" tal:define="value python:request.form.getvalue(name)"> <option value="" i18n:translate="">don't care</option> <metal:slot define-slot="extra_options" /> <option value="" i18n:translate="" disabled="disabled">------------</option> <option tal:repeat="s python:db[db_klass].list()" tal:attributes="value s/id; selected python:value == s.id" tal:content="python:s[db_content]"></option> </select> </td> <td metal:define-macro="search_select_keywords"> <div tal:attributes="id python:'''keywords_%s'''%name"> <select tal:attributes="name name; id name" tal:define="value python:request.form.getvalue(name)"> <option value="" i18n:translate="">don't care</option> <metal:slot define-slot="extra_options" /> <option value="" i18n:translate="" disabled="disabled">------------</option> <option tal:repeat="s python:db[db_klass].list()" tal:attributes="value s/id; selected python:value == s.id" tal:content="python:s[db_content]"></option> </select> <a class="classhelp" tal:attributes="href python:'''javascript:help_window('%s?@template=keywords_expr&property=%s&form=itemSynopsis', 300, 200)'''%(request.classname, name)">(edit)</a> </div> </td> <!-- like search_select, but translates the further values. Could extend it (METAL 1.1 attribute "extend-macro") --> <td metal:define-macro="search_select_translated"> <select tal:attributes="name name; id name" tal:define="value python:request.form.getvalue(name)"> <option value="" i18n:translate="">don't care</option> <metal:slot define-slot="extra_options" /> <option value="" i18n:translate="" disabled="disabled">------------</option> <option tal:repeat="s python:db[db_klass].list()" tal:attributes="value s/id; selected python:value == s.id" tal:content="python:s[db_content]" i18n:translate=""></option> </select> </td> <!-- currently, there is no convenient API to get a list of all roles --> <td metal:define-macro="search_select_roles" tal:define="onchange onchange | nothing"> <select name="roles" id="roles" tal:attributes="onchange onchange"> <option value="" i18n:translate="">don't care</option> <option value="" i18n:translate="" disabled="disabled">------------</option> <option value="User">User</option> <option value="Developer">Developer</option> <option value="Coordinator">Coordinator</option> </select> </td> <td metal:define-macro="search_multiselect"> <input tal:attributes="value python:request.form.getvalue(name) or nothing; name name; id name"/> <span tal:replace="structure python:db[db_klass].classhelp(db_content, property=name, width='600')" /> </td> <td metal:define-macro="search_checkboxes"> <ul class="search-checkboxes" tal:define="value python:request.form.getvalue(name); values python:value and value.split(',') or []"> <li tal:repeat="s python:db[db_klass].list()"> <input type="checkbox" tal:attributes="name name; id string:$name-${s/id}; value s/id; checked python:s.id in values" /> <label tal:attributes="for string:$name-${s/id}" tal:content="python:s[db_content]" /> </li> <li metal:define-slot="no_value_item"> <input type="checkbox" value="-1" tal:attributes="name name; id string:$name--1; checked python:value == '-1'" /> <label tal:attributes="for string:$name--1" i18n:translate="">no value</label> </li> </ul> </td> <td metal:define-macro="column_input"> <input type="checkbox" name="@columns" tal:attributes="value name; checked python:name in cols"/> </td> <td metal:define-macro="sort_input"> <input type="radio" name="@sort" tal:attributes="value name; checked python:name == sort_on"/> </td> <td metal:define-macro="group_input"> <input type="radio" name="@group" tal:attributes="value name; checked python:name == group_on"/> </td> <!-- The following macros are intended for user editing. The invoking context must define a "name" variable which names the property being searched; the "edit_ok" variable tells whether the current user is allowed to edit. See user.item.html in the classic template for examples. --> <script metal:define-macro="user_utils" type="text/javascript" src="@@file/user_utils.js"></script> <!-- src: value will be re-used for other input fields --> <input metal:define-macro="user_src_input" type="text" tal:attributes="onblur python:edit_ok and 'split_name(this)'; id name; name name; value value; readonly not:edit_ok" value="heinz.kunz"/> <!-- normal: no re-using --> <input metal:define-macro="user_normal_input" type="text" tal:attributes="id name; name name; value value; readonly not:edit_ok" value="heinz"/> <!-- password: type; no initial value --> <input metal:define-macro="user_pw_input" spellcheck="false" type="password" tal:attributes="id name; name name; readonly not:edit_ok" value=""/> <input metal:define-macro="user_confirm_input" spellcheck="false" type="password" tal:attributes="id string:confirm_$name; name string:@confirm@$name; readonly not:edit_ok" value=""/> <!-- SHA: ca32e5f43efcb7c3b4940df6f7a176f6990b15f0 -->
