Skip to content

Commit dffe957

Browse files
committed
docs: update README and docs to reflect security improvements
- Document secure default error handler behavior and migration path - Add getConfigOptions() API docs (returns frozen copy) - Update res.send() datatype notes for stream safety and promise depth - Add 5.x section to breaking changes with all security hardening details - Add Security Defaults section to root README
1 parent 4131dcc commit dffe957

2 files changed

Lines changed: 28 additions & 3 deletions

File tree

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,11 @@ service.get('/hi', (req, res) => res.send('Hello World!'))
5757
http.createServer(service).listen(3000, '0.0.0.0')
5858
```
5959

60+
# Security Defaults
61+
Restana ships with secure defaults out of the box:
62+
- **Error handling**: The default error handler returns a generic `Internal Server Error` message, preventing internal details (stack traces, database errors, file paths) from leaking to clients. Provide a custom `errorHandler` to control what gets exposed.
63+
- **Stream safety**: Stream errors are handled gracefully, preventing connection leaks.
64+
- **Immutable config**: `getConfigOptions()` returns a frozen copy, preventing middleware from mutating internal framework options.
65+
6066
# More
6167
- Website and documentation: https://restana.21no.de

docs/README.md

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ Optionally, learn through examples:
8080
- `server`: Allows to optionally override the HTTP server instance to be used.
8181
- `prioRequestsProcessing`: If `TRUE`, HTTP requests processing/handling is prioritized using `setImmediate`. Default value: `TRUE`
8282
- `defaultRoute`: Optional route handler when no route match occurs. Default value: `((req, res) => res.send(404))`
83-
- `errorHandler`: Optional global error handler function. Default value: `(err, req, res) => res.send(err)`
83+
- `errorHandler`: Optional global error handler function. Default value: `(err, req, res) => res.send({ code, message: 'Internal Server Error' }, code)`. The default handler returns a generic error message to prevent leaking sensitive internal details (e.g. database connection strings, file paths, stack traces). The appropriate HTTP status code is still preserved from `err.status`, `err.code`, or `err.statusCode`.
8484
- `routerCacheSize`: The router matching cache size, indicates how many request matches will be kept in memory. Default value: `2000`
8585

8686
# Full service example
@@ -136,6 +136,12 @@ service.start(3000).then((server) => {})
136136
service.close().then(()=> {})
137137
```
138138

139+
## Accessing configuration options
140+
```js
141+
const opts = service.getConfigOptions()
142+
```
143+
> `getConfigOptions()` returns a frozen shallow copy of the configuration options. This prevents third-party middleware from accidentally or maliciously modifying internal framework options at runtime.
144+
139145
## Async / Await support
140146
```js
141147
service.post('/star/:username', async (req, res) => {
@@ -163,8 +169,8 @@ Supported datatypes are:
163169
- String
164170
- Buffer
165171
- Object
166-
- Stream
167-
- Promise
172+
- Stream (errors on the stream are handled gracefully, terminating the response instead of leaving the connection hanging)
173+
- Promise (recursive promise resolution is capped at a depth of 3 to prevent event loop starvation)
168174

169175
Example usage:
170176
```js
@@ -192,6 +198,9 @@ res.send(
192198
> `res.send(401)`
193199
194200
## Global error handling
201+
By default, restana returns a generic `Internal Server Error` message to the client, preventing internal details from being leaked. The HTTP status code is preserved from `err.status`, `err.code`, or `err.statusCode` (defaults to `500`).
202+
203+
To customize error responses, provide your own `errorHandler`:
195204
```js
196205
const service = require('restana')({
197206
errorHandler (err, req, res) {
@@ -204,6 +213,7 @@ service.get('/throw', (req, res) => {
204213
throw new Error('Upps!')
205214
})
206215
```
216+
> **Note:** When using `res.send(err)` in a custom error handler, the error's `message` and `data` properties will be serialized and sent to the client. Make sure your custom handler only exposes information you intend to be public.
207217
### errorHandler not being called?
208218
> Issue: https://github.com/jkyberneees/ana/issues/81
209219
@@ -457,6 +467,15 @@ service.get('/hello', (req, res) => {
457467
https://goo.gl/forms/qlBwrf5raqfQwteH3
458468

459469
# Breaking changes
470+
## 5.x
471+
> Restana version 5.x includes important security hardening while remaining backward compatible for most users.
472+
473+
Changed:
474+
- The default `errorHandler` no longer sends `err.message` or `err.data` to clients. It now returns a generic `{ code, message: 'Internal Server Error' }` response. If you need the previous behavior, provide a custom `errorHandler`.
475+
- `getConfigOptions()` now returns a frozen shallow copy of the options object instead of a direct mutable reference.
476+
- Stream responses (`res.send(stream)`) now handle stream errors gracefully, terminating the response instead of leaving the connection hanging.
477+
- Promise resolution in `res.send()` is now capped at a depth of 3 to prevent event loop starvation from deeply nested promise chains.
478+
460479
## 4.x
461480
> Restana version 4.x is much more simple to maintain, mature and faster!
462481

0 commit comments

Comments
 (0)