Skip to content
Permalink
Browse files Browse the repository at this point in the history
Secure file uploads when NODE_ENV=dev (#487)
  • Loading branch information
jdorn committed Aug 29, 2022
1 parent 289af13 commit 1a5edff
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 2 deletions.
8 changes: 8 additions & 0 deletions packages/back-end/src/controllers/auth.ts
Expand Up @@ -183,6 +183,14 @@ export async function postFirstTimeRegister(
>,
res: Response
) {
// Only allow this API endpoint when it's a brand-new installation with no users yet
const newInstallation = await isNewInstallation();
if (!newInstallation) {
throw new Error(
"An organization is already configured. Please refresh the page and try again."
);
}

const { email, name, password, companyname } = req.body;

validatePasswordFormat(password);
Expand Down
16 changes: 15 additions & 1 deletion packages/back-end/src/services/files.ts
Expand Up @@ -42,7 +42,21 @@ export async function uploadFile(
throw new Error("Invalid upload signature");
}

const fullPath = getUploadsDir() + "/" + filePath;
// Watch out for poison null bytes
if (filePath.indexOf("\0") !== -1) {
throw new Error("Error: Filename must not contain null bytes");
}

const rootDirectory = getUploadsDir();
const fullPath = path.join(rootDirectory, filePath);

// Prevent directory traversal
if (fullPath.indexOf(rootDirectory) !== 0) {
throw new Error(
"Error: Path must not escape out of the 'uploads' directory."
);
}

const dir = path.dirname(fullPath);
await fs.promises.mkdir(dir, { recursive: true });
await fs.promises.writeFile(fullPath, contents);
Expand Down
3 changes: 2 additions & 1 deletion packages/back-end/src/util/secrets.ts
Expand Up @@ -29,6 +29,7 @@ if (!MONGODB_URI) {
}

export const APP_ORIGIN = process.env.APP_ORIGIN || "http://localhost:3000";
const isLocalhost = APP_ORIGIN.includes("localhost");

const corsOriginRegex = process.env.CORS_ORIGIN_REGEX;
export const CORS_ORIGIN_REGEX = corsOriginRegex
Expand Down Expand Up @@ -56,7 +57,7 @@ export const GCS_DOMAIN =
`https://storage.googleapis.com/${GCS_BUCKET_NAME}/`;

export const JWT_SECRET = process.env.JWT_SECRET || "dev";
if (prod && !IS_CLOUD && JWT_SECRET === "dev") {
if ((prod || !isLocalhost) && !IS_CLOUD && JWT_SECRET === "dev") {
throw new Error(
"Cannot use JWT_SECRET=dev in production. Please set to a long random string."
);
Expand Down

0 comments on commit 1a5edff

Please sign in to comment.