Skip to content

Commit f69311f

Browse files
committed
fix: strict token format validation and TOCTOU race in secret store
- Reject session tokens with more or fewer than exactly 2 dot-separated segments in SessionCredentialService.verify() - Add semaphore to ServerSecretStore.getOrCreateRandom() to prevent concurrent read-then-write race condition
1 parent be42c17 commit f69311f

File tree

2 files changed

+11
-2
lines changed

2 files changed

+11
-2
lines changed

apps/server/src/auth/Layers/ServerSecretStore.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as Crypto from "node:crypto";
22

3-
import { Effect, FileSystem, Layer, Path } from "effect";
3+
import { Effect, FileSystem, Layer, Path, Semaphore } from "effect";
44
import * as PlatformError from "effect/PlatformError";
55

66
import { ServerConfig } from "../../config.ts";
@@ -60,6 +60,8 @@ export const makeServerSecretStore = Effect.gen(function* () {
6060
);
6161
};
6262

63+
const mutex = yield* Semaphore.make(1);
64+
6365
const getOrCreateRandom: ServerSecretStoreShape["getOrCreateRandom"] = (name, bytes) =>
6466
get(name).pipe(
6567
Effect.flatMap((existing) => {
@@ -70,6 +72,7 @@ export const makeServerSecretStore = Effect.gen(function* () {
7072
const generated = Crypto.randomBytes(bytes);
7173
return set(name, generated).pipe(Effect.as(Uint8Array.from(generated)));
7274
}),
75+
mutex.withPermits(1),
7376
);
7477

7578
const remove: ServerSecretStoreShape["remove"] = (name) =>

apps/server/src/auth/Layers/SessionCredentialService.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,13 @@ export const makeSessionCredentialService = Effect.gen(function* () {
5656
});
5757

5858
const verify: SessionCredentialServiceShape["verify"] = Effect.fn("verify")(function* (token) {
59-
const [encodedPayload, signature] = token.split(".");
59+
const parts = token.split(".");
60+
if (parts.length !== 2) {
61+
return yield* new SessionCredentialError({
62+
message: "Malformed session token.",
63+
});
64+
}
65+
const [encodedPayload, signature] = parts;
6066
if (!encodedPayload || !signature) {
6167
return yield* new SessionCredentialError({
6268
message: "Malformed session token.",

0 commit comments

Comments
 (0)