diff --git a/src/NATS.Server/Configuration/NatsConfParser.cs b/src/NATS.Server/Configuration/NatsConfParser.cs
index 77fa52a..e948bb8 100644
--- a/src/NATS.Server/Configuration/NatsConfParser.cs
+++ b/src/NATS.Server/Configuration/NatsConfParser.cs
@@ -20,6 +20,9 @@ public static class NatsConfParser
private const string BcryptPrefix2A = "2a$";
private const string BcryptPrefix2B = "2b$";
+ // Maximum nesting depth for include directives to prevent infinite recursion.
+ private const int MaxIncludeDepth = 10;
+
///
/// Parses a NATS configuration string into a dictionary.
///
@@ -34,12 +37,15 @@ public static class NatsConfParser
///
/// Parses a NATS configuration file into a dictionary.
///
- public static Dictionary ParseFile(string filePath)
+ public static Dictionary ParseFile(string filePath) =>
+ ParseFile(filePath, includeDepth: 0);
+
+ private static Dictionary ParseFile(string filePath, int includeDepth)
{
var data = File.ReadAllText(filePath);
var tokens = NatsConfLexer.Tokenize(data);
var baseDir = Path.GetDirectoryName(Path.GetFullPath(filePath)) ?? string.Empty;
- var state = new ParserState(tokens, baseDir);
+ var state = new ParserState(tokens, baseDir, [], includeDepth);
state.Run();
return state.Mapping;
}
@@ -57,7 +63,7 @@ public static class NatsConfParser
var data = Encoding.UTF8.GetString(rawBytes);
var tokens = NatsConfLexer.Tokenize(data);
var baseDir = Path.GetDirectoryName(Path.GetFullPath(filePath)) ?? string.Empty;
- var state = new ParserState(tokens, baseDir);
+ var state = new ParserState(tokens, baseDir, [], includeDepth: 0);
state.Run();
return (state.Mapping, digest);
}
@@ -66,11 +72,11 @@ public static class NatsConfParser
/// Internal: parse an environment variable value by wrapping it in a synthetic
/// key-value assignment and parsing it. Shares the parent's env var cycle tracker.
///
- private static Dictionary ParseEnvValue(string value, HashSet envVarReferences)
+ private static Dictionary ParseEnvValue(string value, HashSet envVarReferences, int includeDepth)
{
var synthetic = $"pk={value}";
var tokens = NatsConfLexer.Tokenize(synthetic);
- var state = new ParserState(tokens, baseDir: string.Empty, envVarReferences);
+ var state = new ParserState(tokens, baseDir: string.Empty, envVarReferences, includeDepth);
state.Run();
return state.Mapping;
}
@@ -84,6 +90,7 @@ public static class NatsConfParser
private readonly IReadOnlyList _tokens;
private readonly string _baseDir;
private readonly HashSet _envVarReferences;
+ private readonly int _includeDepth;
private int _pos;
// The context stack holds either Dictionary (map) or List