dinou 4.0.9 → 4.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
+ ## [4.0.11]
9
+
10
+ ### Fixed
11
+
12
+ - Security: Fix server functions endpoint vulnerability and add improvements.
13
+
14
+ ## [4.0.10]
15
+
16
+ ### Fixed
17
+
18
+ - Server Functions endpoint vulnerability.
19
+
8
20
  ## [4.0.9]
9
21
 
10
22
  ### Changed
@@ -752,7 +752,7 @@ function isOriginAllowed(req) {
752
752
  try {
753
753
  // Parse to ignore protocol (http/https) and port if they differ subtly
754
754
  const originHost = new URL(origin).host;
755
- const serverHost = req.headers.host;
755
+ const serverHost = req.headers["x-forwarded-host"] || req.headers.host;
756
756
 
757
757
  // Compare host (domain:port)
758
758
  return originHost === serverHost;
@@ -782,7 +782,7 @@ app.post("/____server_function____", async (req, res) => {
782
782
 
783
783
  // 1. Check Origin (Prevent calls from other domains)
784
784
  const origin = req.headers.origin;
785
- const host = req.headers.host;
785
+ const host = req.headers["x-forwarded-host"] || req.headers.host;
786
786
 
787
787
  // Note: Locally sometimes origin is undefined or null, allow in dev if necessary
788
788
  if (!isDevelopment && origin && !origin.includes(host)) {
@@ -851,10 +851,15 @@ app.post("/____server_function____", async (req, res) => {
851
851
 
852
852
  // Extract relativePath and normalize (remove 'file://' and potential '/')
853
853
  let relativePath = fileUrl.replace(/^file:\/\/\/?/, "").trim();
854
- if (relativePath.startsWith("/") || relativePath.includes("..")) {
854
+ const normalizedRelative = relativePath.replace(/\\/g, "/");
855
+ if (
856
+ normalizedRelative.startsWith("/") ||
857
+ normalizedRelative.includes("..") ||
858
+ normalizedRelative.includes(":")
859
+ ) {
855
860
  return res
856
861
  .status(400)
857
- .json({ error: "Invalid path: no absolute or traversal allowed" });
862
+ .json({ error: "Invalid path: no absolute, traversal, or drive letter allowed" });
858
863
  }
859
864
  // console.log("relPath", relativePath);
860
865
  // Restrict to 'src/' folder: prepend 'src/' if missing, and resolve absolutePath
@@ -881,6 +886,11 @@ app.post("/____server_function____", async (req, res) => {
881
886
  // Prod: use manifest (relativePath is already normalized)
882
887
  allowedExports = serverFunctionsManifest[relativePath];
883
888
  } else {
889
+ if (!isDevelopment) {
890
+ return res
891
+ .status(403)
892
+ .json({ error: "Access denied: Manifest missing in production" });
893
+ }
884
894
  const fileContent = readFileSync(absolutePath, "utf8"); // Reads only once
885
895
  if (!useServerRegex.test(fileContent)) {
886
896
  return res
@@ -895,7 +905,8 @@ app.post("/____server_function____", async (req, res) => {
895
905
  // Validate exportName against allowedExports
896
906
  if (
897
907
  !exportName ||
898
- (exportName !== "default" && !allowedExports.has(exportName))
908
+ !allowedExports ||
909
+ !allowedExports.has(exportName)
899
910
  ) {
900
911
  return res.status(400).json({ error: "Invalid export name" });
901
912
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dinou-ejected",
3
- "version": "4.0.9",
3
+ "version": "4.0.11",
4
4
  "main": "index.js",
5
5
  "private": true,
6
6
  "exports": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dinou",
3
- "version": "4.0.9",
3
+ "version": "4.0.11",
4
4
  "description": "Full-Stack React 19 framework with React Server Components, Server Functions, and Streaming SSR.",
5
5
  "main": "index.js",
6
6
  "bin": {