Skip to content

[Bug] Regex validators like "^embedding|keywords|blend$" accept values that only contain a keyword #7877

Open

Description

@goranai

Contact Information

No response

MaxKB Version

v2 branch, commit 2900bd8

Problem Description

Many serializer fields check an enum with a pattern like ^embedding|keywords|blend$. In regex, | splits the whole pattern. So this means ^embedding OR keywords OR blend$. Django's RegexValidator uses search, so any value that starts with embedding, contains keywords, or ends with blend is accepted. xkeywords, keywordsx and not_keywords_valid all pass.

The same shape is in 16 places across 10 files:

  • search_mode: apps/application/chat_pipeline/step/search_dataset_step/i_search_dataset_step.py, apps/application/flow/step_node/search_knowledge_node/i_search_knowledge_node.py, apps/application/serializers/application.py, apps/knowledge/serializers/knowledge.py (two places)
  • application type ^SIMPLE|WORK_FLOW$, comparer ^and|or$, hit_handling_method, export type ^csv|excel$, sync type ^replace|complete$
  • tool node input type and source (i_tool_node.py), trigger input source
  • valid_type ^application|knowledge|user$ in apps/system_manage/serializers/valid_serializers.py
  • email code type ^register|reset_password$ in apps/users/serializers/user.py (two places)

ToolInputField in apps/tools/serializers/tool.py has the same two patterns. Nothing references that class, so I left it alone.

The bad value is used later. For example search_mode goes to SearchMode(search_mode) and raises ValueError: 'xkeywords' is not a valid SearchMode. valid_type goes to model_message_dict.get(valid_type), which returns None, and then .get('count') raises AttributeError. Both give a 500 instead of a 400 with the validator message.

Steps to Reproduce

import re
re.compile("^embedding|keywords|blend$").search("xkeywords")   # matches, so the validator accepts it
re.compile("^(embedding|keywords|blend)$").search("xkeywords") # None

I put each of the 16 patterns in a DRF CharField with RegexValidator, like the real serializers. I compared the current patterns with the grouped ones using 57,668 cases per side. The cases were neighbor values, 3,000 mutations of each valid value per pattern, and random strings. The current patterns wrongly accepted 12,445 of them. The grouped patterns accepted 0, and no valid value was rejected. A Hypothesis property with 3,000 examples also passed. A DRF serializer with the same patterns accepts search_mode=xkeywords and valid_type=xuser before the fix and returns 400 after it.

I did not run the full app (it needs Postgres and Redis). So the 500 is shown on the same classes and dict, not through the HTTP route.

The expected correct result

Only the exact values pass, for example embedding, keywords and blend. Anything else gets a 400 with the validator message.

Related log output

ValueError: 'xkeywords' is not a valid SearchMode

Additional Information

Fix: Wrap the alternation in a group: ^(embedding|keywords|blend)$. Same change for every pattern. The set of allowed values stays the same. I will open a PR.

valid_type allows knowledge, but model_message_dict in valid_serializers.py has the key dataset, not knowledge. So valid/knowledge/50 still gives None.get and a 500, before and after this change. No UI code calls it with knowledge. This is a separate bug. I can open another issue if you want.

Validated with Claude Opus 5.5.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions