Skip to content

Conversation

@rcbjBlueMars
Copy link
Contributor

@rcbjBlueMars rcbjBlueMars commented Nov 1, 2025

OAuth2 Implicit Grant + Test working.

} catch(e) {
log.error("An error occurred while retrieving the claim description XML: " + e.stack);
res.status(500)
.render('error', { error: e });

Check warning

Code scanning / CodeQL

Information exposure through a stack trace Medium

This information exposed to the user depends on
stack trace information
.

Copilot Autofix

AI about 1 hour ago

To fix the information exposure via stack trace, we should ensure that information sent to the user contains only generic error details, while any detailed error logs (including stack traces) are retained only in server logs. Specifically:

  • In file api/server.js, at line 119, replace res.render('error', { error: e }); with a more generic response.
  • Log the complete error (including stack trace) server-side using log.error, as is already done.
  • For the user response, send only a general message, such as "An unexpected error occurred." or a structured error object containing a generic message and sanitized code, but never expose stack traces or internal exception details.
  • If standardized error codes or models are used (such as Swagger), ensure the structure matches expectations, but content remains generic.

No change to imports is required; use only standard logging.


Suggested changeset 1
api/server.js

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/api/server.js b/api/server.js
--- a/api/server.js
+++ b/api/server.js
@@ -116,7 +116,11 @@
   } catch(e) {
     log.error("An error occurred while retrieving the claim description XML: " + e.stack);
     res.status(STATUS_500)
-       .render('error', { error: e });
+       .json({
+         status: false,
+         code: 'UNEXPECTED_ERROR',
+         message: 'An unexpected error occurred.'
+       });
   }
 });
 
EOF
@@ -116,7 +116,11 @@
} catch(e) {
log.error("An error occurred while retrieving the claim description XML: " + e.stack);
res.status(STATUS_500)
.render('error', { error: e });
.json({
status: false,
code: 'UNEXPECTED_ERROR',
message: 'An unexpected error occurred.'
});
}
});

Copilot is powered by AI and may make mistakes. Always verify output.
…rom token_detail or userinfo views. Userinfo has a backend processing option and works correctly with POST method.
Comment on lines +344 to +349
axios({
method: 'get',
url: Buffer.from(req.query.userinfo_endpoint, 'base64').toString('utf-8'),
headers: headers,
httpsAgent: new (require('https').Agent)({ rejectUnauthorized: true })
})

Check failure

Code scanning / CodeQL

Server-side request forgery Critical

The
URL
of this request depends on a
user-provided value
.

Copilot Autofix

AI about 1 hour ago

To fix the SSRF issue, we need to ensure the outgoing request’s URL cannot be arbitrarily set by the user. The most robust standard fix is to restrict the target host/domain with an allow-list, so that only pre-approved endpoints can be used. For example, instead of using any URL provided by the user, the code should map a user-supplied identifier (such as an alias or region code) to a specific endpoint from a list of known safe URLs. If the architecture requires the full URL, then strict validation (e.g., regex, hostname checking, path disallowing local/internal services) must be implemented.

In this case, we should:

  • Define an allow-list of permitted endpoints (e.g., in an object mapping of endpoint aliases to URLs).
  • Accept from the client only either: (a) an alias key that selects the real endpoint, or (b) a base64 value and then check the decoded URL against the allow-list.
  • If the value does not match any allowed endpoint, reject the request with an error status and message.

Steps (in file api/server.js):

  1. Add a mapping (object) of allowed endpoints (e.g., OIDC issuers’ userinfo URLs).
  2. In userinfo_common, fetch either an alias or a URL, decode it if needed, and check that it matches the allowed endpoints.
  3. If valid, proceed with the request. If not, respond with 400 (Bad Request) and error message.
  4. Optionally, log invalid attempts for audit.
  5. No additional imports are necessary.

Suggested changeset 1
api/server.js

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/api/server.js b/api/server.js
--- a/api/server.js
+++ b/api/server.js
@@ -331,51 +331,66 @@
   log.debug("Leaving app.get for /userinfo.");
 });
 
+// Allowed OIDC UserInfo endpoints (replace with your valid endpoints)
+const ALLOWED_USERINFO_ENDPOINTS = [
+  "https://accounts.google.com/o/oauth2/v3/userinfo",
+  "https://login.microsoftonline.com/common/openid/userinfo",
+  // Add more allowed endpoints here
+];
+
 function userinfo_common(req, res) {
-try {
-  log.info('Entering app.get for /userinfo.');
-  var headers = {
-    "Authorization": req.headers.authorization,
-  };
-  // All types of requests are converted to GET.
-  log.debug("Method: GET");
-  log.debug("URL: " + Buffer.from(req.query.userinfo_endpoint, 'base64').toString('utf-8'));
-  log.debug("headers: " + JSON.stringify(headers));
-  axios({
-      method: 'get',
-      url: Buffer.from(req.query.userinfo_endpoint, 'base64').toString('utf-8'),
-      headers: headers,
-      httpsAgent: new (require('https').Agent)({ rejectUnauthorized: true })
-    })
-    .then(function (response) {
-      log.debug('Response from OIDC UserInfo Endpoint: ' + JSON.stringify(response.data));
-      log.debug('Headers: ' + response.headers);
-      res.status(response.status);
-      res.json(response.data);
-    })
-    .catch(function (error) {
-      log.error('Error from OIDC UserInfo Endpoint: ' + error);
-      if(!!error.response) {
-        if(!!error.response.status) {
-          log.error("Error Status: " + error.response.status);
+  try {
+    log.info('Entering app.get for /userinfo.');
+    var headers = {
+      "Authorization": req.headers.authorization,
+    };
+    // All types of requests are converted to GET.
+    log.debug("Method: GET");
+    let decodedUrl = Buffer.from(req.query.userinfo_endpoint, 'base64').toString('utf-8');
+    log.debug("Decoded userinfo_endpoint: " + decodedUrl);
+    log.debug("headers: " + JSON.stringify(headers));
+
+    if (!ALLOWED_USERINFO_ENDPOINTS.includes(decodedUrl)) {
+      log.error("Denied userinfo_endpoint: " + decodedUrl);
+      res.status(400).json({ error: "Requested endpoint is not allowed." });
+      return;
+    }
+
+    axios({
+        method: 'get',
+        url: decodedUrl,
+        headers: headers,
+        httpsAgent: new (require('https').Agent)({ rejectUnauthorized: true })
+      })
+      .then(function (response) {
+        log.debug('Response from OIDC UserInfo Endpoint: ' + JSON.stringify(response.data));
+        log.debug('Headers: ' + response.headers);
+        res.status(response.status);
+        res.json(response.data);
+      })
+      .catch(function (error) {
+        log.error('Error from OIDC UserInfo Endpoint: ' + error);
+        if(!!error.response) {
+          if(!!error.response.status) {
+            log.error("Error Status: " + error.response.status);
+          }
+          if(!!error.response.data) {
+            log.error("Error Response body: " + JSON.stringify(error.response.data));
+          }
+          if(!!error.response.headers) {
+            log.error("Error Response headers: " + error.response.headers);
+          }
+          if (!!error.response) {
+            res.status(error.response.status);
+            res.json(error.response.data);
+          } else {
+            res.status(STATUS_500);
+            res.json(error.message);
+          }
         }
-        if(!!error.response.data) {
-          log.error("Error Response body: " + JSON.stringify(error.response.data));
-        }
-        if(!!error.response.headers) {
-          log.error("Error Response headers: " + error.response.headers);
-        }
-        if (!!error.response) {
-          res.status(error.response.status);
-          res.json(error.response.data);
-        } else {
-          res.status(STATUS_500);
-          res.json(error.message);
-        }
-      }
-    });
+      });
   } catch(e) {
-    log.error("Error from OIDC UserInfo Endpoint: " + error);
+    log.error("Error from OIDC UserInfo Endpoint: " + e);
   }
 }
 
EOF
Copilot is powered by AI and may make mistakes. Always verify output.

app.use(bodyParser.json());
var corsOptions = {
origin: '*',

Check warning

Code scanning / CodeQL

Permissive CORS configuration Medium

CORS Origin allows broad access due to
permissive or user controlled value
.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants