-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
fix(integrations): Fix security vulnerabilities in Jira #112409
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
7eed62c
7fc4602
0deeb99
80d877e
4e0e5a3
af7091b
b20f977
30a7fcd
3d2c180
02c42be
16c17c1
3e7afa4
0d2da12
b0b411c
f0be9b7
a48ed95
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| import sentry_sdk | ||
| from django.db import router, transaction | ||
| from jwt import DecodeError, ExpiredSignatureError, InvalidKeyError, InvalidSignatureError | ||
| from rest_framework import status | ||
| from rest_framework.request import Request | ||
| from rest_framework.response import Response | ||
|
|
@@ -20,9 +21,6 @@ | |
| ) | ||
| from sentry.utils import jwt | ||
|
|
||
| # Atlassian sends scanner bots to "test" Atlassian apps and they often hit this endpoint with a bad kid causing errors | ||
| INVALID_KEY_IDS = ["fake-kid"] | ||
|
|
||
|
|
||
| @control_silo_endpoint | ||
| class JiraSentryInstalledWebhook(JiraWebhookBase): | ||
|
|
@@ -46,7 +44,14 @@ | |
| lifecycle.record_failure(ProjectManagementFailuresReason.INSTALLATION_STATE_MISSING) | ||
| return self.respond(status=status.HTTP_400_BAD_REQUEST) | ||
|
|
||
| key_id = jwt.peek_header(token).get("kid") | ||
| try: | ||
| key_id = jwt.peek_header(token).get("kid") | ||
| except DecodeError: | ||
| lifecycle.record_halt(halt_reason="Failed to fetch key id") | ||
| return self.respond( | ||
| {"detail": "Failed to fetch key id"}, status=status.HTTP_400_BAD_REQUEST | ||
| ) | ||
|
|
||
| lifecycle.add_extras( | ||
| { | ||
| "key_id": key_id, | ||
|
|
@@ -56,14 +61,34 @@ | |
| } | ||
| ) | ||
|
|
||
| if key_id: | ||
| if key_id in INVALID_KEY_IDS: | ||
| lifecycle.record_halt(halt_reason="JWT contained invalid key_id (kid)") | ||
| return self.respond( | ||
| {"detail": "Invalid key id"}, status=status.HTTP_400_BAD_REQUEST | ||
| ) | ||
| if not key_id: | ||
| lifecycle.record_halt(halt_reason="Missing key_id (kid)") | ||
| return self.respond( | ||
| {"detail": "Missing key id"}, status=status.HTTP_400_BAD_REQUEST | ||
| ) | ||
| try: | ||
| decoded_claims = authenticate_asymmetric_jwt(token, key_id) | ||
| verify_claims(decoded_claims, request.path, request.GET, method="POST") | ||
| except InvalidKeyError: | ||
| lifecycle.record_halt(halt_reason="JWT contained invalid key_id (kid)") | ||
sentry[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return self.respond( | ||
| {"detail": "Invalid key id"}, status=status.HTTP_400_BAD_REQUEST | ||
| ) | ||
cursor[bot] marked this conversation as resolved.
Show resolved
Hide resolved
cursor[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| except ExpiredSignatureError as e: | ||
| lifecycle.record_failure(e) | ||
| return self.respond( | ||
| {"detail": "Expired signature"}, status=status.HTTP_400_BAD_REQUEST | ||
| ) | ||
| except InvalidSignatureError: | ||
| lifecycle.record_halt(halt_reason="JWT contained invalid signature") | ||
| return self.respond( | ||
| {"detail": "Invalid signature"}, status=status.HTTP_400_BAD_REQUEST | ||
| ) | ||
| except DecodeError: | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we broaden this to cover all exceptions?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On a similar note, we should add some tests for these cases to ensure error handling doesn't allow the pipeline to continue, and responds with the correct status code.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added tests for the specific errors we're catching including a |
||
| lifecycle.record_halt(halt_reason="Could not decode JWT token") | ||
| return self.respond( | ||
| {"detail": "Could not decode JWT token"}, status=status.HTTP_400_BAD_REQUEST | ||
| ) | ||
|
Check warning on line 91 in src/sentry/integrations/jira/webhooks/installed.py
|
||
sentry[bot] marked this conversation as resolved.
Show resolved
Hide resolved
ceorourke marked this conversation as resolved.
Show resolved
Hide resolved
ceorourke marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| data = JiraIntegrationProvider().build_integration(state) | ||
| integration = ensure_integration(self.provider, data) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.