Commit graph

39 commits

Author SHA1 Message Date
Manish Gupta
30527927d7
[WEB-8103] fix: stop leaking webhook HMAC secret_key on reads (#9382)
* [WEB-8103] fix: stop leaking webhook HMAC secret_key on reads (GHSA-83rj)

WebhookEndpoint list/retrieve/patch pass a fields= allowlist that excludes
secret_key, but DynamicBaseSerializer.__init__ discards the caller
allowlist (fields = self.expand). With WebhookSerializer using
fields="__all__" and secret_key only in read_only_fields (read-only is
still serialized), the HMAC signing secret leaked on every webhook read
(GHSA-83rj-4282-x39v; admin-only).

Rather than secret_key = CharField(write_only=True) — which would let a
client inject their own secret on create/patch and break the intended
one-time reveal — hide it by default and reveal only where intended:

- WebhookSerializer.to_representation drops secret_key unless the
  show_secret_key context flag is set (secure by default). secret_key
  stays server-generated (default=generate_token) and non-writable.
- POST create and WebhookSecretRegenerateEndpoint pass show_secret_key so
  the secret is still returned once for the caller to configure their
  receiver; list/retrieve/patch no longer emit it.

Add contract regression tests (fail-before verified). Follow-up: the
DynamicBaseSerializer.__init__ allowlist bug affects other serializers —
tracked separately.

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

* [WEB-8103] test: address review — patch network boundary + pin to_representation

Per review (@sriramveeraghanta):
- Patch the network boundary (validate_url) instead of the whole private
  _validate_webhook_url method, so the domain/schema checks still run and
  the test survives a rename of the private method.
- Add an assertion that an explicit fields=("secret_key",) request still
  hides the key, pinning to_representation as the enforcement point so a
  future DynamicBaseSerializer._filter_fields fix can't silently re-open
  the leak.

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

* [WEB-8103] docs: spell out both levels of the dead fields= allowlist

The previous comment named only DynamicBaseSerializer.__init__ discarding the
caller's fields=, which is half the root cause. _filter_fields never removes
anything either: it builds `allowed` purely to attach expansion serializers for
names not already on the serializer, then returns self.fields unfiltered
(serializers/base.py:45-119).

So the fields= kwargs in views/webhook/base.py are no-ops on two independent
levels. Documented so a future `fields = fields or self.expand` fix isn't
assumed to re-activate the allowlists for confidentiality — _filter_fields has
to be made restrictive first. The show_secret_key context flag remains the sole
enforcement point.

Addresses @sriramveeraghanta's review on #9382. 6/6 contract tests pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* 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>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 00:16:01 +05:30
Manish Gupta
4b52dce76e
[WEB-7855] fix(security): prevent project invite email disclosure via unauthenticated GET (#9305)
ProjectJoinEndpoint.get() was AllowAny and used ProjectMemberInviteSerializer
(fields = "__all__"), leaking the invitee's email and token to anyone who
knew the workspace slug, project ID, and invite UUID (GHSA-2r58-hgv7-635q).

Introduce ProjectMemberInvitePublicSerializer with an explicit safe field list
that excludes `email` and `token`, and swap it in for the public GET endpoint.
The full serializer is retained for authenticated admin viewsets.

Co-authored-by: Plane AI <noreply@plane.so>
2026-07-01 17:34:45 +05:30
Manish Gupta
0d58adb69d
[WEB-7774] fix(security): sanitize comment_html and intake description_html with nh3 (#9287)
GHSA-6qrq-f73q-r67j / GHSA-j9pv-f5wm-p4g2 — IssueCommentSerializer in
both app and api layers stored comment_html without sanitization. The app
layer had no validate() at all; the api layer only ran lxml structural
normalization which does not strip XSS payloads.

Fix: both serializers now call validate_html_content() (nh3-backed) in
their validate() methods, replacing the raw value with sanitized HTML.

GHSA-hh2r-3hwp-mvq3 — space/views/intake.py and api/views/intake.py
both used bare Issue.objects.create() with description_html taken
directly from request data, bypassing any serializer validation.

Fix: both paths now call validate_html_content() and pass the sanitized
value to Issue.objects.create(). Falls back to "<p></p>" if sanitizer
returns None (empty/invalid input).

The nh3 sanitizer (validate_html_content in content_validator.py) was
already present and used by IssueCreateSerializer — this change extends
coverage to the two remaining unsanitized comment and intake paths.

Co-authored-by: Plane AI <noreply@plane.so>
2026-06-23 17:52:31 +05:30
Manish Gupta
6220ba990b
[WEB-7854] fix: prevent workspace invite token disclosure and invite hijack (#9297)
- Add WorkSpaceMemberInvitePublicSerializer that excludes token and
  invite_link; use it in WorkspaceJoinEndpoint.get() so an unauthenticated
  caller cannot retrieve the acceptance token from the GET endpoint
  (GHSA-86mg-259g-pwgg / GHSA-gf48-p6jp-cwc4).
- Require authentication and verify request.user.email matches the
  invited email before accepting a workspace invitation so an attacker
  who registers with the invited address cannot hijack the invite
  (GHSA-4vj8-p63v-8p24).

Co-authored-by: Plane AI <noreply@plane.so>
2026-06-23 17:47:16 +05:30
sriram veeraghanta
7b0704d9cc
fix(api): require at least one alphanumeric char in workspace name (#9278)
* fix(api): require at least one alphanumeric char in workspace name

Workspace name validation was enforced only on the frontend
(validateWorkspaceName), which gates the UI submit but is bypassable
via a direct API call. The backend WorkSpaceSerializer.validate_name
only rejected URLs, so a symbol-only name like "-_________-" could
still be saved via create or the rename (partial_update) path.

Add a Unicode-aware has_alphanumeric() helper and enforce it in both
the app and instance/license workspace serializers, mirroring the
frontend HAS_ALPHANUMERIC_REGEX (/[\p{L}\p{N}]/u) added in #9263.
International names (日本語, José, محمد) still pass since str.isalnum()
covers all scripts.

Adds unit tests covering symbol-only rejection and international
acceptance on both serializers.

Refs #9255

Signed-off-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>

* fix(api): reject URLs in instance workspace name for parity

Address CodeRabbit review on #9278: the instance/license
WorkspaceSerializer.validate_name rejected symbol-only names but, unlike
the app-level WorkSpaceSerializer, still accepted names containing URLs.
Add the same contains_url() guard (imported from plane.utils.url, not
content_validator) so both workspace-create paths validate identically.

Add unit tests asserting URL-containing names are rejected on both
serializers.

Signed-off-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>

---------

Signed-off-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>
2026-06-20 17:36:37 +05:30
sriram veeraghanta
edf2475413
refactor: logging with retention + API token hardening (#9148)
* fix: harden API token handling against rate-limit tampering and plaintext logging

- Make `allowed_rate_limit` read-only on APITokenSerializer so users can no
  longer raise their own API token rate limit via PATCH (GHSA-xfgr-2x3f-g2cf).
- Stop persisting API keys in plaintext in APITokenLogMiddleware: store a
  SHA-256 hash as the token identifier and redact sensitive request headers
  (X-Api-Key, Authorization, Cookie) before logging (GHSA-r5p8-cj3q-38cc).

* refactor: remove MongoDB log sink and add per-log-type retention

Logs are now written to and cleared from PostgreSQL only; MongoDB is no
longer used as a log sink or archive.

- Drop the MongoDB write/archival paths from the API request logger, the
  webhook log writer, and the cleanup tasks; Postgres is the sole sink.
- Cleanup tasks now hard-delete expired rows in batches via `all_objects`
  (rows are removed immediately, not soft-deleted).
- Add env-backed, per-log-type retention settings: API activity logs
  (API_ACTIVITY_LOG_RETENTION_DAYS, default 14), webhook logs
  (WEBHOOK_LOG_RETENTION_DAYS, default 14), email logs
  (EMAIL_LOG_RETENTION_DAYS, default 7). HARD_DELETE_AFTER_DAYS no longer
  drives any log cleanup.
- Delete settings/mongo.py, remove MONGO_DB_* settings and the plane.mongo
  loggers, and drop the pymongo dependency.

* chore: gitignore local advisories.md notes file

* fix: use keyed HMAC-SHA256 for API token log identifier

Address CodeQL "weak hashing of sensitive data" by hashing the API key with
a SECRET_KEY-keyed HMAC instead of a bare SHA-256. The identifier is a
non-reversible tokenization of a high-entropy key (not password storage);
keying it also prevents precomputing the digest from a known key value.

* chore: address review feedback on log cleanup and request logging

- process_logs accepts extra kwargs so jobs enqueued by an older release
  (with a mongo_log arg) don't fail during a rolling deploy.
- Log-cleanup batch delete failures are logged and skipped rather than
  aborting the run, so a single bad batch can't block the rest.
- Extend logger middleware test to assert Authorization and Cookie headers
  are redacted; add a test that a failing cleanup batch is swallowed.

* fix: fall back to default when a log retention env value is invalid

Negative (or unparseable) retention values would compute a future cutoff and
delete every log row. The retention settings now fall back to their defaults
in that case via a shared `_retention_days` helper.
2026-05-27 16:00:05 +05:30
Sangeetha
e71a8f5dbb
[GIT-174]chore: set completed_at as read only field for work item (#9083) 2026-05-25 14:01:50 +05:30
sriram veeraghanta
761c999e0c
fix: add WEBHOOK_ALLOWED_HOSTS allowlist for internal webhook targets (#9078)
* fix: add WEBHOOK_ALLOWED_HOSTS allowlist for internal webhook targets

The IP-based allowlist alone isn't practical for containerised deployments
where service IPs are dynamic. Adds a hostname-based bypass for trusted
internal services (e.g. Silo via docker-compose / k8s service DNS) and
makes the previously hardcoded ["plane.so"] domain blocklist configurable
via WEBHOOK_DISALLOWED_DOMAINS.

- validate_url accepts allowed_hosts (exact, case-insensitive match;
  skips DNS lookup for trusted names)
- WebhookSerializer wires both settings through and lets allowlisted
  hosts bypass the disallowed-domain check
- Exposes WEBHOOK_ALLOWED_HOSTS in aio/cli deployment env files

* fix: default WEBHOOK_DISALLOWED_DOMAINS to empty for self-hosted

* fix: pass WEBHOOK_ALLOWED_HOSTS to send-time webhook re-validation
2026-05-15 00:57:39 +05:30
sriram veeraghanta
a8a16c8ba0
fix: replace IS_SELF_MANAGED with WEBHOOK_ALLOWED_IPS allowlist (#8884)
* fix: replace IS_SELF_MANAGED toggle with explicit WEBHOOK_ALLOWED_IPS allowlist

Instead of blanket-allowing all private IPs on self-managed deployments,
webhook URL validation now blocks all private/internal IPs by default and
only permits specific networks listed in the WEBHOOK_ALLOWED_IPS env
variable (comma-separated IPs/CIDRs).

* fix: address PR review comments for webhook SSRF protection

- Sanitize error messages to avoid leaking internal details to clients
- Guard against TypeError with mixed IPv4/IPv6 allowlist networks
- Re-validate webhook URL at send time to prevent DNS-rebinding
- Add unit tests for mixed-version IP network allowlists
2026-04-20 15:28:33 +05:30
sriram veeraghanta
71b0d30afb
[SECUR-116] fix: ssrf webhook url for ip address #8716 2026-03-05 17:26:06 +05:30
Sangeetha
c4b3d52466
[WEB-5878] chore: add validation for project name/identifier for special characters (#8529)
* chore: update ProjectSerializer to raise validation for special characters in name and identifier

* chore: update external endpoints

* fix: external api serializer validation

* update serializer to send error code

* fix: move the regex expression to Project model
2026-02-17 00:49:02 +05:30
Dheeraj Kumar Ketireddy
ef5d481a19
[VPAT-51] fix: update workspace invitation flow to use token for validation #8508
- Modified the invite link to include a token for enhanced security.
- Updated the WorkspaceJoinEndpoint to validate the token instead of the email.
- Adjusted the workspace invitation task to generate links with the token.
- Refactored the frontend to handle token in the invitation process.

Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
2026-02-17 00:02:18 +05:30
Sangeetha
78729277e8
[SECUR-104] fix: Arbitrary Modification of API Token Rate Limits#8612 2026-02-09 14:50:29 +05:30
sriram veeraghanta
02d0ee3e0f
chore: add copyright (#8584)
* feat: adding new copyright info on all files

* chore: adding CI
2026-01-27 13:54:22 +05:30
Bavisetti Narayan
2a29ab8d4a
[WEB-5845] chore: changing description field to description json (#8230)
* chore: migrating description to description json

* chore: replace description with description_json

* chore: updated migration file

* chore: updated the migration file

* chore: added description key in external endpoint

* chore: updated the migration file

* chore: updated the typo

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2026-01-22 18:23:59 +05:30
Nikhil
ea1f92e0c6
[WEB-5537]refactor: rename IssueUserProperty to ProjectUserProperty and update related references (#8206)
* refactor: rename IssueUserProperty to ProjectUserProperty and update related references across the codebase

* migrate: move issue user properties to project user properties and update related fields and constraints

* refactor: rename IssueUserPropertySerializer and IssueUserDisplayPropertyEndpoint to ProjectUserPropertySerializer and ProjectUserDisplayPropertyEndpoint, updating all related references

* fix: enhance ProjectUserDisplayPropertyEndpoint to handle missing properties by creating new entries and improve response handling

* fix: correct formatting in migration for ProjectUserProperty model options

* migrate: add migration to update existing non-service API tokens to remove workspace association

* migrate: refine migration to update existing non-service API tokens by excluding bot users from workspace removal

* chore: changed the project sort order in project user property

* chore: remove allowed_rate_limit from APIToken

* chore: updated user-properties endpoint for frontend

* chore: removed the extra projectuserproperty

* chore: updated the migration file

* chore: code refactor

* fix: type error

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
Co-authored-by: sangeethailango <sangeethailango21@gmail.com>
Co-authored-by: vamsikrishnamathala <matalav55@gmail.com>
Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia@plane.so>
2026-01-06 15:37:19 +05:30
sriram veeraghanta
777200db7b
chore: workspace events (#8439)
* chore: adding invite and joined events

* chore: adding workspace create and update events
2025-12-23 19:47:00 +05:30
Sangeetha
df710e00dc
[WEB-5666] chore: set project timezone same as workspace timezone in project (#8340) 2025-12-16 20:46:53 +05:30
Anmol Singh Bhatia
2ac5efe2f0
[WEB-5647] chore: list layout work item identifier enhancements (#8326) 2025-12-12 19:21:29 +05:30
sriram veeraghanta
c7bf912cf2
fix: state group choices (#8198) 2025-11-28 18:06:00 +05:30
Bavisetti Narayan
78fbdde165
[WEB-5282] chore: triage state in intake (#8135)
* chore: traige state in intake

* chore: triage state changes

* feat: implement intake state dropdown component and integrate into issue properties

* chore: added the triage state validation

* chore: added triage state filter

* chore: added workspace filter

* fix: migration file

* chore: added triage group state check

* chore: updated the filters

* chore: updated the filters

* chore: added variables for intake state

* fix: import error

* refactor: improve project intake state retrieval logic and update TriageGroupIcon component

* chore: changed the intake validation logic

* refactor: update intake state types and clean up unused interfaces

* chore: changed the state color

* chore: changed the update serializer

* chore: updated with current instance

* chore: update TriageGroupIcon color to match new intake state group color

* chore: stringified value

* chore: added validation in serializer

* chore: added logger instead of print

* fix: correct component closing syntax in ActiveProjectItem

* chore: updated the migration file

* chore: added noop in migation

---------

Co-authored-by: b-saikrishnakanth <bsaikrishnakanth97@gmail.com>
2025-11-28 16:16:48 +05:30
Sangeetha
c31a225775
[WEB-5506] fix: new navigation pre release bugs (#8181)
* chore: update navigation_project_limit and navigation_control_preference

* chore: set default true for user specific widgets

* chore: use serializer in ProjectMemberPreferenceEndpoint
chore: use serializer in WorkspaceUserPropertiesEndpoint
"

* fix: validate preferences

* fix: status code

* fix: remove saving from validate

* fix: simply validate_preferences

* chore: create WorkspaceUserProperties if it doesn't exist

* fix: create WorksapceUserProperties it not exist

* fix: copy the instance

* Revert "fix: copy the instance"

This reverts commit ddb0384b6dfa0dc52929972c4e2cd7ce85c69667.

* chore: migrate WorkspaceUserPreference to set defaults

* fix: migration file name

* Revert "fix: migration file name"

This reverts commit 80a21dedf1a1245f22e45bfeaf20e8e9f91a1cbf.

* Revert "chore: migrate WorkspaceUserPreference to set defaults"

This reverts commit 25bc583a081ce79d52ec721f69cf8e61de3e8fb3.
2025-11-27 18:12:20 +05:30
Sangeetha
7c8cbc4ead
[WEB-4428] fix: duplicate labels with case insensitive (#7388)
Co-authored-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>
2025-11-24 21:22:17 +05:30
sriram veeraghanta
9237f568dd
[WEB-5044] fix: ruff lint and format errors (#7868)
* fix: lint errors

* fix: file formatting

* fix: code refactor
2025-09-29 19:15:32 +05:30
Nikhil
1fb22bd252
[WEB-4805] fix: upgraded psycopgy packages to fix linting and removed unused imports (#7735)
* chore: update psycopg dependencies to version 3.2.9 in base requirements

* refactor: clean up unused imports across multiple files

* chore: update lxml dependency to version 6.0.0 in base requirements

* style: improve code readability by breaking long lines into multiple lines across several files

* style: enhance readability by breaking long lines in ModuleSerializer docstring
2025-09-29 14:33:50 +05:30
Bavisetti Narayan
9182c9593b
[WIKI-657] refactor: the page permissions in project (#7761) 2025-09-18 20:14:46 +05:30
sriram veeraghanta
c3e7cfd16b
[WEB-4723] fix: disable project features on project create (#7625)
* fix: disbale project features on project create

* Implement migration 0105 to alter project cycle view fields to Boolean with default values

* Add project view settings in workspace seed task

* Add is_current_version_deprecated field to Instance model

Index user_id field in Session model

---------

Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
2025-09-12 13:01:03 +05:30
Anmol Singh Bhatia
56cd0fc445
[WEB-4025] fix: external user comment and reaction (#7692)
* chore: reactions types updated

* fix: external user comments

* fix: external user reactions

* chore: added display name for actor

* chore: merge conflicts

* chore: updated the created_by and updated_by

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
2025-09-09 23:50:11 +05:30
Bavisetti Narayan
0af75897f5
[WEB-4780] chore: changed the html validation (#7648)
* chore: changed the html validation

* chore: added requirements for nh3

* chore: removed the json validations
2025-08-27 00:38:25 +05:30
Anmol Singh Bhatia
d0f26f8734
[WEB-4726] fix: intake work item redirection (#7619)
* chore: added is intake for email notifications

* fix: intake work item redirection

* chore: code refactor

* chore: code refactor

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
2025-08-22 12:54:46 +05:30
Sangeetha
27fa439c8d
[WEB-4602] fix: 500 error on draft wi labels update #7515 2025-07-30 20:18:48 +05:30
sriramveeraghanta
c4d2c5b1bb sync: canary changes to preview 2025-07-30 15:44:41 +05:30
Bavisetti Narayan
d4705e1649 [WEB-4544] chore: added field validations in serializer (#7460)
* chore: added field validations in serializer

* chore: added enum for roles
2025-07-30 15:41:44 +05:30
Bavisetti Narayan
69d5cd183f
chore: added validation for description (#7507)
* added PageBinaryUpdateSerializer for binary data validation and update

* chore: added validation for description

* chore: removed the duplicated file

* Fixed coderabbit comments

- Improve content validation by consolidating patterns and enhancing recursion checks

- Updated `PageBinaryUpdateSerializer` to simplify assignment of validated data.
- Enhanced `content_validator.py` with consolidated dangerous patterns and added recursion depth checks to prevent stack overflow during validation.
- Improved readability and maintainability of validation functions by using constants for patterns.

---------

Co-authored-by: Dheeraj Kumar Ketireddy <dheeru0198@gmail.com>
2025-07-30 14:19:49 +05:30
Bavisetti Narayan
63d025cbf4
[WEB-4544] chore: added field validations in serializer (#7460)
* chore: added field validations in serializer

* chore: added enum for roles
2025-07-25 16:50:35 +05:30
Sangeetha
ec0ef98c1b
[WEB-4281] chore: error code on project updation endpoint (#7218) 2025-07-17 13:05:24 +05:30
Prateek Shourya
67b62dcbe3
[WEB-4498] improvement: remove workspace details from workspace members list API (#7407)
* [WEB-4498] improvement: remove workspace details from workspace members list API

* refactor: update select_related usage in workspace invitation and member views

---------

Co-authored-by: Dheeraj Kumar Ketireddy <dheeru0198@gmail.com>
2025-07-14 20:45:23 +05:30
sriram veeraghanta
6ce700fd5d
chore: format files using prettier (#7364)
* chore: format files using prettier

* chore: api server files formatted
2025-07-08 20:41:11 +05:30
sriram veeraghanta
fdbe4c2ca6
chore: rename server to api (#7342) 2025-07-04 15:32:21 +05:30