Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Python: NAMED_ARG_REGEX character-class bug [${1}] lets non-$-prefixed values ({, 1, }) be silently parsed as variable references

Open Beginner friendly
#14,491 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 2 days

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
85/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
python
Domain
backend

Research direction

Start at python/semantic_kernel/template_engine/blocks/named_arg_block.py, line 21, and reproduce the listed NamedArgBlock cases to confirm the regex behavior. Update the variable-form matching so only a literal $ prefix is accepted, then verify that $var still parses and 1var, {var, and }var raise NamedArgBlockSyntaxError.

Written by the indexing model from the issue text.

Description

python triage

What happens

NamedArgBlock's parsing regex, NAMED_ARG_REGEX, is supposed to require a named argument's variable form to start with a literal $ (per the grammar: [parameter] ::= [variable] | [value] and [variable] ::= "$" [valid-name]). Because of a regex mistake, it instead accepts a variable reference whose first character is $, {, 1, or } and always treats the rest as the variable name, silently dropping that first character. This means unquoted, non-$-prefixed argument text that starts with 1, {, or } is silently reinterpreted as a variable substitution instead of raising a syntax error, and the value actually used at render time comes from an unrelated kernel argument instead of the text the template author wrote.

Where

python/semantic_kernel/template_engine/blocks/named_arg_block.py, line 21:

NAMED_ARG_REGEX = r"^(?P<name>[0-9A-Za-z_]+)[=]{1}(?P<value>[${1}](?P<var_name>[0-9A-Za-z_]+)|(?P<quote>[\"'])(?P<val>.[^\"^']*)(?P=quote))$"

The variable-form alternative is [${1}](?P<var_name>...). Inside a character class, {1} is not a quantifier, it is three literal characters {, 1, }. So [${1}] is a 4-character class matching any one of $, {, 1, } — not "a literal $, exactly once" as the {1} clearly was intended to express (that would need to be written outside the brackets, e.g. \$ or [$]).

Why

Confirmed directly against the regex and the real class, on semantic-kernel==1.44.1 (byte-identical to current main for this file):

from semantic_kernel.template_engine.blocks.named_arg_block import NamedArgBlock

for content in ["arg1=$var", "arg1={var", "arg1=1var", "arg1=}var"]:
    b = NamedArgBlock(content=content)
    print(content, "-> name=", b.name, "variable=", b.variable)

Output:

arg1=$var -> name= arg1 variable= content='$var' name='var'
arg1={var -> name= arg1 variable= content='{var' name='var'
arg1=1var -> name= arg1 variable= content='1var' name='var'
arg1=}var -> name= arg1 variable= content='}var' name='var'

All four are accepted and all four produce a VarBlock pointing at the variable named var, even though only the first one actually starts with $. The {, 1, and } prefixes are silently swallowed instead of causing a NamedArgBlockSyntaxError (which is what happens for any other non-$/non-quote prefix, e.g. arg1=Xvar is correctly rejected).

Full end-to-end repro (real rendering, not just the regex)

import asyncio
from semantic_kernel import Kernel
from semantic_kernel.functions.kernel_arguments import KernelArguments
from semantic_kernel.functions.kernel_function_decorator import kernel_function
from semantic_kernel.prompt_template.kernel_prompt_template import KernelPromptTemplate
from semantic_kernel.prompt_template.prompt_template_config import PromptTemplateConfig

class MyPlugin:
    @kernel_function(name="echo")
    def echo(self, arg1: str) -> str:
        return f"GOT[{arg1}]"

kernel = Kernel()
kernel.add_plugin(MyPlugin(), plugin_name="my")

async def main():
    args = KernelArguments(var="SECRET_VALUE")
    template_str = "{{ my.echo arg1=1var }}"   # arg1 is meant to be the literal text "1var"
    tpl = KernelPromptTemplate(prompt_template_config=PromptTemplateConfig(template=template_str))
    print(await tpl.render(kernel, args))

asyncio.run(main())

Output:

GOT[SECRET_VALUE]

Expected vs actual

  • Expected: arg1=1var does not match the [variable] grammar rule ("$" [valid-name]), so it should either be rejected with NamedArgBlockSyntaxError (consistent with arg1=Xvar, which is correctly rejected) or, if unquoted plain-text arguments were meant to be legal, treated as the literal text 1var. Either way arg1 should never end up holding the value of an unrelated kernel argument called var.
  • Actual: the call silently succeeds and arg1 is substituted with args["var"] ("SECRET_VALUE"), not the text the template author wrote. The same happens for any unquoted, non-quoted value that happens to start with { or }.

Suggested fix

Move the quantifier out of the character class so only a literal $ starts the variable form, e.g.:

NAMED_ARG_REGEX = r"^(?P<name>[0-9A-Za-z_]+)=(?P<value>\$(?P<var_name>[0-9A-Za-z_]+)|(?P<quote>[\"'])(?P<val>.[^\"^']*)(?P=quote))$"

Environment

  • semantic-kernel 1.44.1 (PyPI), verified byte-for-byte identical against python/semantic_kernel/template_engine/blocks/named_arg_block.py on the current main branch.
  • Python 3.13, Windows.
Dominant language
C#
Stars
28.6k
Forks
4.8k
Avg merge
12h 20m
Merged PRs (30d)
12

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from microsoft/semantic-kernel

All issues in microsoft/semantic-kernel

Similar issues

More C# issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.