Skip to content

bug: mcpp new accepts unsafe names and can hang during template rendering #380

Description

@wellwei

Summary

mcpp new <name> currently has no single authoritative project-name contract. The name is used both as a filesystem path and as unescaped template data. This permits path escape and malformed generated projects; one valid-looking input can also make the command loop forever.

Reproduction

1. Template marker in the name hangs the command

mcpp new PROJECT
mcpp new myPROJECTname

The builtin scaffold repeatedly executes:

while ((pos = body.find("PROJECT")) != std::string::npos) {
    body.replace(pos, 7, name);
}

When name itself contains PROJECT, the replacement result remains matchable. A controlled 500 ms run ended with ETIMEDOUT / SIGTERM; mcpp.toml had already been created, leaving a partial project.

The package-template renderer has the same general risk because inserted placeholder values are searched again by replace_all when they contain the placeholder token.

2. A name can escape the current directory

mkdir work
cd work
mcpp new ../escaped

Observed result: exit code 0 and the project was created at the parent directory (../escaped). Both builtin and package-template paths construct the destination as current_path() / name without requiring a single path component.

3. Template-unsafe names return success with invalid files

mcpp new 'bad"name'
mcpp new $'bad\tname'

Observed result: exit code 0. The generated TOML/C++ contains the value without escaping, for example:

name = "bad"name"

The builtin scaffold also does not check the open/write status of mcpp.toml, src/main.cpp, tests/test_smoke.cpp, or .gitignore, so an incomplete write can still reach the success message and return 0.

Expected behavior

Before creating any directory, mcpp new should apply one shared validation contract to builtin and package templates:

  • require a non-empty single path component;
  • reject absolute paths, separators, . / .., control characters, and platform-invalid names;
  • either reject template-unsafe characters or provide context-safe escaping;
  • render placeholders without rescanning inserted values;
  • check every directory/file operation and return non-zero on incomplete output;
  • avoid leaving a partial project after a failed render/write where practical.

The CLI should own this contract so VS Code and other clients do not need to copy internal template rules.

Suggested tests

  • PROJECT and myPROJECTname terminate and produce valid output or a clear validation error.
  • ../escaped and an absolute path cannot create outside the working directory.
  • quotes and C0/DEL controls cannot produce malformed TOML/C++.
  • failed file writes return non-zero.
  • the same name validation applies to builtin and package-shipped templates.

Environment and evidence boundary

  • Runtime reproduction: locally available mcpp 2026.8.5.2 on macOS ARM64.
  • Current-source verification: origin/main@fdad165 (v2026.8.8.2) still contains the same destination construction, unescaped builtin template replacement, and unchecked output streams.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions