fix: use constant-time comparison for API key validation#33986
fix: use constant-time comparison for API key validation#33986xr843 wants to merge 9 commits intolanggenius:mainfrom
Conversation
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
Pyrefly Diffbase → PR--- /tmp/pyrefly_base.txt 2026-03-24 00:08:55.984484758 +0000
+++ /tmp/pyrefly_pr.txt 2026-03-24 00:08:47.136528613 +0000
@@ -21,9 +21,9 @@
ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
--> controllers/console/human_input_form.py:190:70
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
- --> controllers/console/init_validate.py:31:2
+ --> controllers/console/init_validate.py:32:2
ERROR Object of class `MissingRouter` has no attribute `post` [missing-attribute]
- --> controllers/console/init_validate.py:44:2
+ --> controllers/console/init_validate.py:45:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
--> controllers/console/ping.py:10:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
|
Pyrefly Diffbase → PR--- /tmp/pyrefly_base.txt 2026-03-24 00:11:06.123580148 +0000
+++ /tmp/pyrefly_pr.txt 2026-03-24 00:10:55.856481113 +0000
@@ -21,9 +21,9 @@
ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
--> controllers/console/human_input_form.py:190:70
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
- --> controllers/console/init_validate.py:31:2
+ --> controllers/console/init_validate.py:32:2
ERROR Object of class `MissingRouter` has no attribute `post` [missing-attribute]
- --> controllers/console/init_validate.py:44:2
+ --> controllers/console/init_validate.py:45:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
--> controllers/console/ping.py:10:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
|
Pyrefly Diffbase → PR--- /tmp/pyrefly_base.txt 2026-03-28 07:16:39.949555767 +0000
+++ /tmp/pyrefly_pr.txt 2026-03-28 07:16:29.880518904 +0000
@@ -11,9 +11,9 @@
ERROR Argument `str | None` is not assignable to parameter `language` with type `str` in function `services.account_service.AccountService.send_email_register_email` [bad-argument-type]
--> controllers/console/auth/email_register.py:78:108
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
- --> controllers/console/init_validate.py:31:2
+ --> controllers/console/init_validate.py:32:2
ERROR Object of class `MissingRouter` has no attribute `post` [missing-attribute]
- --> controllers/console/init_validate.py:44:2
+ --> controllers/console/init_validate.py:45:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
--> controllers/console/ping.py:10:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
|
|
Hi team, gentle ping on this PR. It replaces direct string comparison of API keys with |
|
fix conflict |
- data_source.py: scope patch() query by tenant_id to prevent cross-tenant data source binding access (IDOR vulnerability) - test_auth_wraps.py: update mock to match db.session.query() API instead of db.session.get() Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
d07f74d to
8ccdba9
Compare
|
Rebased on latest main to resolve the merge conflict. CI is green — would appreciate a review when you have a chance. 🙏 This is a straightforward security improvement: replacing direct string comparison of API keys with |
Pyrefly Diffbase → PR--- /tmp/pyrefly_base.txt 2026-04-02 23:20:35.914689118 +0000
+++ /tmp/pyrefly_pr.txt 2026-04-02 23:20:27.219668118 +0000
@@ -3,9 +3,9 @@
ERROR Argument `str | None` is not assignable to parameter `language` with type `str` in function `services.account_service.AccountService.send_email_register_email` [bad-argument-type]
--> controllers/console/auth/email_register.py:78:108
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
- --> controllers/console/init_validate.py:31:2
+ --> controllers/console/init_validate.py:32:2
ERROR Object of class `MissingRouter` has no attribute `post` [missing-attribute]
- --> controllers/console/init_validate.py:44:2
+ --> controllers/console/init_validate.py:45:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
--> controllers/console/ping.py:10:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
|
The test_patch_binding_scoped_to_current_tenant test was mocking 'Session' which no longer exists in the source module. Updated to mock 'sessionmaker' with the correct .begin() context manager chain. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pyrefly Diffbase → PR--- /tmp/pyrefly_base.txt 2026-04-03 02:11:54.132962680 +0000
+++ /tmp/pyrefly_pr.txt 2026-04-03 02:11:45.354934748 +0000
@@ -3,9 +3,9 @@
ERROR Argument `str | None` is not assignable to parameter `language` with type `str` in function `services.account_service.AccountService.send_email_register_email` [bad-argument-type]
--> controllers/console/auth/email_register.py:78:108
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
- --> controllers/console/init_validate.py:31:2
+ --> controllers/console/init_validate.py:32:2
ERROR Object of class `MissingRouter` has no attribute `post` [missing-attribute]
- --> controllers/console/init_validate.py:44:2
+ --> controllers/console/init_validate.py:45:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
--> controllers/console/ping.py:10:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
|
|
Hi maintainers, this PR has been passing all CI checks for a while now. Could someone take a look when you have a moment? The change adds constant-time comparison for API key validation to prevent timing attacks. Thanks! 🙏 |
There was a problem hiding this comment.
Pull request overview
This PR hardens authentication and tenant-scoped lookups by switching sensitive token comparisons to constant-time checks and tightening a data source binding lookup to prevent cross-tenant access.
Changes:
- Replace
==/!=withhmac.compare_digest()for API key / secret comparisons in multiple auth-related code paths. - Scope
DataSourceOauthBindingpatch lookup bytenant_idto mitigate IDOR risk. - Add/adjust tests to validate the tenant scoping and updated inner-api user lookup mocking.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| api/controllers/console/admin.py | Constant-time comparison for admin API key validation. |
| api/controllers/console/auth/oauth_server.py | Constant-time comparison + None guards for OAuth client secret validation. |
| api/controllers/console/extension.py | Constant-time comparison when deciding whether to overwrite masked API key value. |
| api/controllers/console/init_validate.py | Constant-time comparison for init password validation with missing-env guard. |
| api/controllers/inner_api/wraps.py | Constant-time comparison for inner API keys and enterprise HMAC signature; user fetch logic adjusted. |
| api/extensions/ext_login.py | Constant-time comparison for admin API key auth in request loader. |
| api/libs/token.py | Constant-time comparison for admin API key bypass in CSRF check. |
| api/services/tools/mcp_tools_manage_service.py | Constant-time comparisons when preserving masked client credentials. |
| api/controllers/console/datasets/data_source.py | Patch query filters DataSourceOauthBinding by tenant_id (IDOR mitigation). |
| api/tests/test_containers_integration_tests/controllers/console/datasets/test_data_source.py | Adds test asserting tenant scoping on patch binding lookup. |
| api/tests/unit_tests/controllers/inner_api/test_auth_wraps.py | Updates mocking to match new session query-based user retrieval. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
api/tests/test_containers_integration_tests/controllers/console/datasets/test_data_source.py
Outdated
Show resolved
Hide resolved
|
Friendly bump — this PR adds constant-time comparison for API key validation and prevents an IDOR issue. Happy to address any feedback. Thanks! |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Pyrefly Diffbase → PR--- /tmp/pyrefly_base.txt 2026-04-07 00:28:00.539381436 +0000
+++ /tmp/pyrefly_pr.txt 2026-04-07 00:27:52.618393031 +0000
@@ -3,9 +3,9 @@
ERROR Argument `str | None` is not assignable to parameter `language` with type `str` in function `services.account_service.AccountService.send_email_register_email` [bad-argument-type]
--> controllers/console/auth/email_register.py:78:108
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
- --> controllers/console/init_validate.py:31:2
+ --> controllers/console/init_validate.py:32:2
ERROR Object of class `MissingRouter` has no attribute `post` [missing-attribute]
- --> controllers/console/init_validate.py:44:2
+ --> controllers/console/init_validate.py:45:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
--> controllers/console/ping.py:10:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Update test mock to match wraps.py which uses db.session.get(EndUser, user_id) instead of the query chain pattern. Session.get() is the correct approach for primary key lookups. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Head branch was pushed to by a user without write access
Pyrefly Diffbase → PR--- /tmp/pyrefly_base.txt 2026-04-07 13:15:43.859141686 +0000
+++ /tmp/pyrefly_pr.txt 2026-04-07 13:15:34.164063189 +0000
@@ -3,9 +3,9 @@
ERROR Argument `str | None` is not assignable to parameter `language` with type `str` in function `services.account_service.AccountService.send_email_register_email` [bad-argument-type]
--> controllers/console/auth/email_register.py:78:108
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
- --> controllers/console/init_validate.py:31:2
+ --> controllers/console/init_validate.py:32:2
ERROR Object of class `MissingRouter` has no attribute `post` [missing-attribute]
- --> controllers/console/init_validate.py:44:2
+ --> controllers/console/init_validate.py:45:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
--> controllers/console/ping.py:10:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
|
Pyrefly Diffbase → PR--- /tmp/pyrefly_base.txt 2026-04-07 13:15:45.366217631 +0000
+++ /tmp/pyrefly_pr.txt 2026-04-07 13:15:36.912218122 +0000
@@ -3,9 +3,9 @@
ERROR Argument `str | None` is not assignable to parameter `language` with type `str` in function `services.account_service.AccountService.send_email_register_email` [bad-argument-type]
--> controllers/console/auth/email_register.py:78:108
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
- --> controllers/console/init_validate.py:31:2
+ --> controllers/console/init_validate.py:32:2
ERROR Object of class `MissingRouter` has no attribute `post` [missing-attribute]
- --> controllers/console/init_validate.py:44:2
+ --> controllers/console/init_validate.py:45:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
--> controllers/console/ping.py:10:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
|
…ing matching Address Copilot review feedback: check for tenant_id in WHERE clause structure rather than matching exact compiled SQL text, which can vary across SQLAlchemy versions/dialects. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pyrefly Diffbase → PR--- /tmp/pyrefly_base.txt 2026-04-12 13:47:04.764903142 +0000
+++ /tmp/pyrefly_pr.txt 2026-04-12 13:46:55.637879231 +0000
@@ -3,9 +3,9 @@
ERROR Argument `str | None` is not assignable to parameter `language` with type `str` in function `services.account_service.AccountService.send_email_register_email` [bad-argument-type]
--> controllers/console/auth/email_register.py:75:108
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
- --> controllers/console/init_validate.py:31:2
+ --> controllers/console/init_validate.py:32:2
ERROR Object of class `MissingRouter` has no attribute `post` [missing-attribute]
- --> controllers/console/init_validate.py:44:2
+ --> controllers/console/init_validate.py:45:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
--> controllers/console/ping.py:10:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
|
Pyrefly Diffbase → PR--- /tmp/pyrefly_base.txt 2026-04-12 13:48:48.114881733 +0000
+++ /tmp/pyrefly_pr.txt 2026-04-12 13:48:40.179998387 +0000
@@ -3,9 +3,9 @@
ERROR Argument `str | None` is not assignable to parameter `language` with type `str` in function `services.account_service.AccountService.send_email_register_email` [bad-argument-type]
--> controllers/console/auth/email_register.py:75:108
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
- --> controllers/console/init_validate.py:31:2
+ --> controllers/console/init_validate.py:32:2
ERROR Object of class `MissingRouter` has no attribute `post` [missing-attribute]
- --> controllers/console/init_validate.py:44:2
+ --> controllers/console/init_validate.py:45:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
--> controllers/console/ping.py:10:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
|
Summary
==withhmac.compare_digest()for API key and secret comparisons to prevent timing attackstenant_idcheck inDataSourceOauthBindingqueries to prevent IDOR vulnerabilitiesRebased on latest main to resolve CI failures from #33858 (which were caused by upstream test issues, now fixed in #33896 and #33899).
Supersedes #33858.