Copilot commented on code in PR #13708:
URL: https://github.com/apache/trafficserver/pull/13708#discussion_r4068008965


##########
plugins/experimental/access_control/access_control.cc:
##########
@@ -29,6 +29,50 @@
 size_t calcMessageDigest(const StringView hf, const char *secret, const char 
*message, size_t messageLen, char *buffer, size_t len);
 const char *getSecretMap(const StringMap &map, const StringView &key, size_t 
&secretSize);
 
+static String
+normalizePath(StringView path)
+{
+  if (path.empty()) {
+    return "/";
+  }
+
+  String decoded(path.size(), '\0');
+  size_t decodedLen = urlDecode(path.data(), path.size(), decoded.data(), 
decoded.size());

Review Comment:
   `urlDecode()` applies `application/x-www-form-urlencoded` semantics and 
converts `+` to a space (`utils.cc:156-157`), but `+` is a literal character in 
an HTTP URL path. As a result, a scope such as `/reports+archive` also 
authorizes `/reports%20archive` (and vice versa), even though these are 
distinct path segments to the origin. Decode percent escapes for path matching 
without translating `+`.



##########
plugins/experimental/access_control/access_control.cc:
##########
@@ -29,6 +29,50 @@
 size_t calcMessageDigest(const StringView hf, const char *secret, const char 
*message, size_t messageLen, char *buffer, size_t len);
 const char *getSecretMap(const StringMap &map, const StringView &key, size_t 
&secretSize);
 
+static String
+normalizePath(StringView path)
+{
+  if (path.empty()) {
+    return "/";
+  }
+
+  String decoded(path.size(), '\0');
+  size_t decodedLen = urlDecode(path.data(), path.size(), decoded.data(), 
decoded.size());

Review Comment:
   This feeds the counted request path to `urlDecode`, whose `%` branch reads 
`src[1]` and `src[2]` without checking that those bytes are within `inLen` 
(`utils.cc:149-155`). A request path ending in `%` or `%a` can therefore 
trigger an out-of-bounds read while enforcing a token. Make the decoder 
length-aware (or reject/handle incomplete escapes) before using it here.



##########
plugins/experimental/access_control/access_control.cc:
##########
@@ -470,6 +513,29 @@ accessTokenStatusToString(const AccessTokenStatus &state)
   return s;
 }
 
+/**
+ * Validates the request path against the token scope using normalized segment 
boundaries.
+ */
+bool
+validateScope(StringView requestPath, StringView scope)
+{
+  if (scope.empty()) {
+    return true;
+  }
+  String normRequestPath = normalizePath(requestPath);
+  String normScope       = normalizePath(scope);
+  if (normScope == "/") {
+    return true;

Review Comment:
   Canonicalizing `..` in the scope itself can broaden a token's authorization: 
a signed scope such as `/reports/..` normalizes to `/`, and the next branch 
treats `/` as unrestricted. The request path should be normalized for 
comparison, but scopes containing traversal segments should be rejected as 
invalid rather than converted into a broader scope.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to