jira/apps/api/plane/utils
Manish Gupta d25b99cae2
[WEB-8110] fix: sanitize page list order_by against an allowlist (#9387)
* [WEB-8110] fix: sanitize page list order_by against an allowlist (GHSA-2v48)

PageViewSet.get_queryset passed the raw order_by query param into
.order_by(). In Django 4.2 .order_by() resolves field names at call time,
so an unknown field (e.g. order_by=password) raises FieldError → 500 DoS,
and a valid relation path (e.g. order_by=owned_by__password) enables ORM
relational traversal (GHSA-2v48-qcjw-74ch).

Add PAGE_ORDER_BY_ALLOWLIST to utils/order_queryset.py and wrap the param
with the existing sanitize_order_by() before it reaches .order_by(),
matching the issue/project/view/notification endpoints. Unknown or
malformed values fall back to the safe -created_at default.

Covers only the app project-pages residual; the 3 external-REST-API sites
in the advisory are handled by PR #9348. EE Wiki counterpart: WEB-8111.

Add contract regression tests (fail-before verified).

Co-authored-by: Plane AI <noreply@plane.so>

* [WEB-8110] fix: fold sanitized order_by into a single order_by() call (review)

Address CodeRabbit + Copilot on #9387: the sanitized .order_by(user) was
immediately overridden by a later .order_by("-is_favorite", "-created_at"),
so the order_by param had no effect on the result (dead code) and cost an
extra query-build step.

Merge them into one .order_by("-is_favorite", <sanitized>, "id") — matching
the EE project-pages viewset — so favourites stay pinned first, the
allowlisted user ordering actually applies as the secondary sort, and id is
a stable pagination tiebreak. The no-param default is unchanged
(-created_at). Add a test asserting order_by=name / -name actually reorders
the results.

Co-authored-by: Plane AI <noreply@plane.so>

* chore(security): drop advisory identifiers from code comments

Explanations kept unchanged; only the IDs are removed.

Co-authored-by: Plane AI <noreply@plane.so>

---------

Co-authored-by: Plane AI <noreply@plane.so>
2026-08-28 00:16:47 +05:30
..
core chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30
exporters fix(api): sanitize XLSX export cells to prevent formula injection (#9224) 2026-06-10 11:32:13 +05:30
filters [WEB-8477] fix: created_at/updated_at filters return no work items (#9513) 2026-07-30 19:51:16 +05:30
instance_config_variables [GIT-243]fix: InstanceConfiguration not created for some keys (#9303) 2026-07-29 19:33:02 +05:30
openapi [SILO-1026] feat: add estimates external API endpoints (#8664) 2026-03-30 15:30:02 +05:30
permissions [WEB-8095] fix: scope page-version reads to the URL project (GHSA-g49r/ghcr) (#9380) 2026-07-16 16:03:06 +05:30
porters fix(api): sanitize XLSX export cells to prevent formula injection (#9224) 2026-06-10 11:32:13 +05:30
__init__.py chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30
analytics_plot.py fix: prevent ORM field injection via segment parameter in analytics (GHSA-93x3-ghh7-72j3) (#8864) 2026-04-07 16:04:48 +05:30
build_chart.py chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30
cache.py chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30
color.py chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30
constants.py chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30
content_validator.py fix(api): require at least one alphanumeric char in workspace name (#9278) 2026-06-20 17:36:37 +05:30
csv_utils.py fix(api): sanitize XLSX export cells to prevent formula injection (#9224) 2026-06-10 11:32:13 +05:30
cycle_transfer_issues.py fix: cast avatar_asset to CharField to resolve mixed type errors in URL concatenation (#9512) 2026-07-30 20:29:41 +05:30
date_utils.py chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30
email.py [WEB-5917] fix: generate clean plain text from HTML email template #8535 2026-02-17 00:44:52 +05:30
error_codes.py chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30
exception_logger.py chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30
global_paginator.py chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30
grouper.py chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30
host.py chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30
html_processor.py chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30
imports.py chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30
ip_address.py fix: harden webhook/link/OAuth-avatar SSRF (advisory clusters A/B/C/E) (#9163) 2026-05-31 00:12:23 +05:30
issue_filters.py [WEB-8477] fix(api): filter "Updated At" by updated_at column, not created_at (#9514) 2026-07-30 20:30:21 +05:30
issue_relation_mapper.py chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30
issue_search.py chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30
logging.py chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30
markdown.py chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30
order_queryset.py [WEB-8110] fix: sanitize page list order_by against an allowlist (#9387) 2026-08-28 00:16:47 +05:30
otlp_endpoints.py [WEB-7447] feat: migrate CE telemetry from OTLP traces to OTLP metrics (#9156) 2026-05-28 18:34:27 +05:30
paginator.py [WEB-8012] fix: prevent ORM group_by/sub_group_by injection in issue endpoints (#9347) 2026-07-13 20:40:01 +05:30
path_validator.py fix: strip control characters from sanitized filenames (#9151) 2026-07-28 17:52:46 +05:30
timezone_converter.py chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30
url.py chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30
url_security.py fix: harden webhook/link/OAuth-avatar SSRF (advisory clusters A/B/C/E) (#9163) 2026-05-31 00:12:23 +05:30
uuid.py chore: add copyright (#8584) 2026-01-27 13:54:22 +05:30