Comparing version 0.15.3 to 0.15.4
@@ -6,2 +6,21 @@ # Change Log | ||
### [0.15.4](https://github.com/endojs/endo/compare/ses@0.15.3...ses@0.15.4) (2022-01-23) | ||
### Features | ||
* **ses:** Check early for dynamic evalability ([d0f6f09](https://github.com/endojs/endo/commit/d0f6f099d41edee3f484da5d5094848f72f93084)), closes [#343](https://github.com/endojs/endo/issues/343) | ||
### Bug Fixes | ||
* **ses:** Direct eval check should not preclude no-eval under CSP ([#1004](https://github.com/endojs/endo/issues/1004)) ([fc8f9ee](https://github.com/endojs/endo/commit/fc8f9eee5ec703ebc611bc015b94fc8ecb721324)) | ||
* **ses:** Fix mistaken this binding example ([#990](https://github.com/endojs/endo/issues/990)) ([71db876](https://github.com/endojs/endo/commit/71db876ee3d7557f0f19dd995a4e027cc7945c2b)) | ||
* minor wording ([#989](https://github.com/endojs/endo/issues/989)) ([f8d6ff6](https://github.com/endojs/endo/commit/f8d6ff6c63b0c46bcaf93378b61d7286d971fd5f)) | ||
* **ses:** Add assert.error options bag to type definition ([#978](https://github.com/endojs/endo/issues/978)) ([ca42997](https://github.com/endojs/endo/commit/ca4299714d5769ea15418612f679abb400ff7e25)), closes [#977](https://github.com/endojs/endo/issues/977) | ||
* **ses:** Number.prototype.toLocaleString radix confusion ([#975](https://github.com/endojs/endo/issues/975)) ([6a17595](https://github.com/endojs/endo/commit/6a175953e5c78d2575c2e9e4e72e6b893bcdb631)), closes [#852](https://github.com/endojs/endo/issues/852) | ||
* **ses:** Remove superfluous error cause on prototypes ([#955](https://github.com/endojs/endo/issues/955)) ([6e50c45](https://github.com/endojs/endo/commit/6e50c4526f457b31e00a783406d175b0088907eb)) | ||
### [0.15.3](https://github.com/endojs/endo/compare/ses@0.15.2...ses@0.15.3) (2021-12-14) | ||
@@ -8,0 +27,0 @@ |
@@ -92,2 +92,3 @@ | ||
export interface AssertMakeErrorOptions { | ||
errorName?: string, | ||
} | ||
@@ -123,3 +124,3 @@ | ||
typeof: AssertTypeof, | ||
error(details?: Details, errorConstructor?:ErrorConstructor): Error; | ||
error(details?: Details, errorConstructor?:ErrorConstructor, options?:AssertMakeErrorOptions): Error; | ||
fail(details?: Details, errorConstructor?:ErrorConstructor): never; | ||
@@ -126,0 +127,0 @@ equal(left: any, right: any, details?: Details, errorConstructor?:ErrorConstructor): void; |
User-visible changes in SES: | ||
# v0.15.3 (2022-01-21) | ||
- Fixes the type definition for assert.error so that the final options bag, | ||
which may include `errorName`, checks correctly in TypeScript. | ||
- Lockdown will now throw an error if code running before SES initialization | ||
replaced `eval`. | ||
# 0.15.2 (2021-12-08) | ||
@@ -4,0 +11,0 @@ |
{ | ||
"name": "ses", | ||
"version": "0.15.3", | ||
"version": "0.15.4", | ||
"description": "Hardened JavaScript for Fearless Cooperation", | ||
@@ -51,3 +51,3 @@ "keywords": [ | ||
"cover": "c8 ava", | ||
"demo": "http-server -o /demos", | ||
"demo": "python3 -m http.server", | ||
"lint": "yarn lint:types && yarn lint:js", | ||
@@ -63,6 +63,6 @@ "lint-fix": "eslint --fix .", | ||
"devDependencies": { | ||
"@endo/compartment-mapper": "^0.6.1", | ||
"@endo/eslint-config": "^0.3.20", | ||
"@endo/static-module-record": "^0.6.8", | ||
"@endo/test262-runner": "^0.1.14", | ||
"@endo/compartment-mapper": "^0.6.2", | ||
"@endo/eslint-config": "^0.3.21", | ||
"@endo/static-module-record": "^0.6.9", | ||
"@endo/test262-runner": "^0.1.15", | ||
"ava": "^3.12.1", | ||
@@ -77,3 +77,2 @@ "babel-eslint": "^10.0.3", | ||
"eslint-plugin-prettier": "^3.1.2", | ||
"http-server": "^0.12.1", | ||
"prettier": "^1.19.1", | ||
@@ -185,3 +184,3 @@ "sinon": "8.0.4", | ||
}, | ||
"gitHead": "8e55edd7840870ec8a78016e1871f056e20145fb" | ||
"gitHead": "b986f1b0afbec1261fb2c047257751b9d418df7c" | ||
} |
214
README.md
@@ -16,3 +16,3 @@ # SES | ||
* **Strict mode** SES enforces JavaScript strict mode that enhances security, | ||
for example by changing some silent errors into throw errors. | ||
for example by changing some silent failures into thrown errors. | ||
* **POLA** (Principle of Least Authority) By default, Compartments receive no | ||
@@ -32,7 +32,6 @@ ambient authority. They are created without host-provided APIs, (for example | ||
Derived from the Caja project, https://github.com/google/caja/wiki/SES. | ||
SES starts where the Caja project left off | ||
https://github.com/google/caja/wiki/SES, and goes on to introduce compartments | ||
and modernize the permitted JavaScript features. | ||
Still under development: do not use for production systems yet, there are | ||
known security holes that need to be closed. | ||
## Install | ||
@@ -99,3 +98,3 @@ | ||
See [`lockdown` options](./lockdown-options.md) for configuration options to | ||
See [`lockdown` options](docs/lockdown.md) for configuration options to | ||
`lockdown`. However, all of these have sensible defaults that should | ||
@@ -219,5 +218,11 @@ work for most projects out of the box. | ||
```js | ||
const f = new Function("return this"); | ||
f() === globalThis | ||
// true | ||
const c1 = new Compartment(); | ||
const f1 = new c.globalThis.Function('return globalThis'); | ||
f1() === c1.globalThis; // true | ||
const c2 = new Compartment(); | ||
const f2 = new c.globalThis.Function('return globalThis'); | ||
f2() === c2.globalThis; // true | ||
f1() === f2(); // false | ||
``` | ||
@@ -254,3 +259,3 @@ | ||
import 'ses'; | ||
import { StaticModuleRecord } from '@endo/static-module-record`; | ||
import { StaticModuleRecord } from '@endo/static-module-record'; | ||
@@ -511,2 +516,191 @@ const c1 = new Compartment({}, {}, { | ||
## Security claims and caveats | ||
The `ses` shim concerns boundaries between programs in the same process and | ||
JavaScript realm. | ||
In terms of the [Taxonomy of Security Issues](https://agoric.com/blog/all/taxonomy-of-security-issues/), | ||
the `ses` shim creates a boundary that is finer than an operating system | ||
process or thread and facilitates boundaries as fine as individual objects. | ||
While `ses` can interpose at granularities where process isolation is not a | ||
viable boundary, as between an application and its dependencies or between a | ||
platform and a plugin, `ses` combines well with coarser boundaries for defense | ||
in depth. | ||
For the purposes of these claims and caveats, a "host program" is a program | ||
that arranges `ses`, calls `lockdown`, and orchestrates one or more "guest | ||
programs", providing limited access to its resources. | ||
Provided that the `ses` implementation and its trusted compute base are | ||
correct, we claim that a host program (Figure 1) can evaluate a guest program | ||
(`program`) in a compartment after `lockdown` and that the program: | ||
- will initially only have access to one mutable object, the compartment's | ||
`globalThis`, | ||
- specifically cannot modify any shared primordial objects, which are part of | ||
the default execution environment, | ||
- cannot initially perform any I/O (except I/O necessarily performed by the | ||
trusted compute base like paging virtual memory), | ||
- and specifically cannot measure the passage of time at any resolution. | ||
However, such a program can: | ||
- execute for an indefinite amount of time, | ||
- allocate arbitrary amounts of memory, | ||
- detect the platform endianness, | ||
- in some JavaScript engines, observe the contents of the stack. | ||
This may include sensitive information about the layout of files on the host | ||
disk. | ||
In cases where the stack is data-dependent, a guest can infer the data. | ||
`ses` occludes the stack on V8 and SpiderMonkey, but cannot on | ||
JavaScriptCore. | ||
```js | ||
// Claims, Figure 1 | ||
lockdown(); | ||
const compartment = new Compartment(); | ||
compartment.evaluate(program); | ||
``` | ||
If the host program (Figure 2) arranges for the compartment's `globalThis` to | ||
be frozen, we additionally claim that the host can evaluate any two guest | ||
programs (`program1` and `program2`) such that neither program will: | ||
- initially share *any* mutable objects. | ||
- be able to observe the relative passage of time of the other program, | ||
as they would had they been given a reference to a working `Date.now()`. | ||
- be able to communicate, as they would if they had shared access to mutable | ||
state like an unfrozen object, a hardened collection like a `Map`, or even | ||
`Math.random()`. | ||
```js | ||
// Claims, Figure 2 | ||
lockdown(); | ||
const compartment = new Compartment(); | ||
harden(compartment.globaThis); | ||
compartment.evaluate(program1); | ||
compartment.evaluate(program2); | ||
``` | ||
However such programs (`program`, `program1`, or `program2`) are only | ||
as useful as a calculator. | ||
A host program is therefore responsible for maintaining any of the desired | ||
invariants above when "endowing" a compartment with any of its own objects. | ||
For example, a host program (Figure 3) may run two programs in separate | ||
compartments, giving one program the ability to resolve a promise and the other | ||
program the ability to observe the settlement (fulfillment or rejection) of | ||
that promise. | ||
The host program is responsible for hardening these objects. | ||
```js | ||
// Claims, Figure 2 | ||
lockdown(); | ||
const promise = new Promise(resolve => { | ||
const compartmentA = new Compartment(harden({ | ||
resolve, | ||
})); | ||
compartment.evaluate(programA); | ||
}); | ||
const compartmentB = new Compartment(harden({ | ||
promise, | ||
})); | ||
compartmentB.evaluate(programB); | ||
``` | ||
With `ses`, guest programs are initially powerless. | ||
A host can explicitly share limited powers with guest programs | ||
and provide intentional communication channels between them. | ||
Host programs must maintain the `ses` boundary with care in what they present | ||
as endowments. | ||
A host program should take care not to share mutable state with guests, | ||
or distribute mutable state to multiple guests, such as an unfrozen object (use | ||
`harden`), direct read and write access to a collection, like a `Map` or `Set`, | ||
even if hardened. | ||
Furthermore, typed arrays are collections and cannot be hardened. | ||
For the purposes of sharing state, pseudo-random number generators (PRNG) like | ||
`Math.random()` are equivalent to read and write access to shared state, and | ||
any guest can use one to eavesdrop on other guests or the host that share one. | ||
If a guest program needs a high resolution timer to function, the host should | ||
only invite one guest to a single operating system process and limit the | ||
activity of the host program in the same process. | ||
Hosts must avoid exposing `SharedArrayBuffer` to guests. | ||
Any two JavaScript programs sharing a `SharedArrayBuffer` can use the shared | ||
buffer to construct a high resolution timer. | ||
The `ses` shim does not in itself isolate the stack of guest programs, even | ||
when evaluated in separate compartments. | ||
This is relevant when program created objects are shared between guest | ||
programs. | ||
When a program interacts with an object introduced by another program (as | ||
through the per-compartment `globalThis`, function arguments or returned | ||
values), there are potential risks due to the synchronous nature of object | ||
access. | ||
Even interactions that are not explicit function calls may cause code from | ||
another program, like property accessors or proxy traps, to execute on the same | ||
stack, which may be able to call back into the program (reentrancy), throw, or | ||
detect the current stack height. | ||
A host object can defend itself from reentrancy attacks by ensuring that it | ||
interacts with guest objects on a clean stack through the use of promises. | ||
Within these constraints, a host program can provide objects that grant limited | ||
I/O capabilities to guest programs, and even revoke or suspend those | ||
capabilities at runtime. | ||
The trusted compute base (TCB) for `ses` includes: | ||
- the host hardware, | ||
- the host operating system, | ||
- any intermediate virtual operating systems or hypervisors, | ||
- the process memory manager, | ||
- an implementation of JavaScript conforming to ECMAScript 262 as of | ||
2021, providing no unspecified embedding host behavior like the introduction of syntax | ||
that when evaluated reveals a mutable object. | ||
`ses` accounts for one such host behavior provided by Node.js, namely the `domain` | ||
property on promises, by preventing the use of `ses` in concert with the | ||
`domain` module. | ||
- Also, any attached debugger, and | ||
- any JavaScript that has executed in the same realm before the host program calls | ||
`lockdown`, including JavaScript that executes after `ses` initializes. | ||
## Audits | ||
In June 2021, `ses` underwent formal third party vulnerability assessment over a | ||
period of 4 weeks with 3 engineers and a dedicated project manager that | ||
surfaced no unknown security issues or vulnerabilities within the code. As a | ||
result of this assessment, [a single code change was | ||
made](https://github.com/endojs/endo/issues/126) to set a flag to disable the | ||
domain module in Node.js to mitigate a known issue identified in the code. The | ||
code will be the subject of another round of intense application security | ||
review mid-2022 by a reputable application security firm renowned for their | ||
results in security reviews. | ||
In July 2021, `ses` was the target of an intensive collaborative bug hunt lead by | ||
the MetaMask team. | ||
No critical flaws in the code surfaced during the review. | ||
As a result of the search for flaws, deficiencies, and weaknesses in the code | ||
(which is currently a Stage 1 proposal with the ECMA TC39 committee), a series | ||
of small code changes and documentation improvements were made. There is a | ||
report available on the | ||
[Agoric blog](https://agoric.com/blog/technology/metamask-agoric-hardened-js-security-review/) | ||
that includes links to recordings of code walk-throughs and technical | ||
discussion, and issues are tagged | ||
[audit-SEStival](https://github.com/endojs/endo/labels/audit-sestival). | ||
In addition to vulnerability assessments, active efforts to [formally verify | ||
the Agoric kernel](https://agoric.com/blog/technology/the-path-to-verified-blds-how-informal-systems-and-agoric-are-using-formal-methods-analysis-to-improve-software-integrity/) | ||
have found the object capability model that `ses` provides to be sound. | ||
Hardened JavaScript is also within the scope of the [Agoric bug bounty | ||
program](hackerone.com/agoric), which rewards researchers for surfacing valid | ||
bugs in our code. We welcome the opportunity to cooperate with researchers, | ||
whose efforts will undoubtedly yield stronger, more resilient code. | ||
## Bug Disclosure | ||
@@ -513,0 +707,0 @@ |
@@ -9,18 +9,31 @@ # Security Policy | ||
| Version | Supported | | ||
| ------- | ------------------ | | ||
| 0.12.x | :white_check_mark: | | ||
## Coordinated Vulnerability Disclosure of Security Bugs | ||
## Reporting a Vulnerability | ||
SES stands for fearless cooperation, and strong security requires strong collaboration with security researchers. If you believe that you have found a security sensitive bug that should not be disclosed until a fix has been made available, we encourage you to report it. To report a bug in HardenedJS, you have several options that include: | ||
Please help us practice coordinated security bug disclosure. If you find a | ||
security-sensitive bug that should not be revealed publically until a fix is | ||
available, please send email to `security` at (@) `agoric.com`. To encrypt, | ||
please use my (@warner) personal GPG key [A476E2E6 11880C98 5B3C3A39 0386E81B | ||
11CAA07A](http://www.lothar.com/warner-gpg.html) . Keybase users can also | ||
send messages to `@agoric_security`, or share code and other log files via | ||
the Keybase encrypted file system | ||
(`/keybase/private/agoric_security,$YOURNAME`). | ||
* Reporting the issue to the [Agoric HackerOne vulnerability rewards program](hackerone.com/agoric). | ||
We will create a GitHub security advisory promptly. Let us know your GitHub | ||
username and we'll add you to the collaborator list for further discussion. | ||
* Sending an email to security at (@) agoric.com., encrypted or unencrypted. To encrypt, please use @Warner’s personal GPG key [A476E2E6 11880C98 5B3C3A39 0386E81B 11CAA07A](http://www.lothar.com/warner-gpg.html) . | ||
* Sending a message on Keybase to `@agoric_security`, or sharing code and other log files via Keybase’s encrypted file system. ((_keybase_private/agoric_security,$YOURNAME). | ||
* It is important to be able to provide steps that reproduce the issue and demonstrate its impact with a Proof of Concept example in an initial bug report. Before reporting a bug, a reporter may want to have another trusted individual reproduce the issue. | ||
* A bug reporter can expect acknowledgment of a potential vulnerability reported through [security@agoric.com](mailto:security@agoric.com) within one business day of submitting a report. If an acknowledgement of an issue is not received within this time frame, especially during a weekend or holiday period, please reach out again. Any issues reported to the HackerOne program will be acknowledged within the time frames posted on the program page. | ||
* The bug triage team and Agoric code maintainers are primarily located in the San Francisco Bay Area with business hours in [Pacific Time](https://www.timeanddate.com/worldclock/usa/san-francisco) . | ||
* For the safety and security of those who depend on the code, bug reporters should avoid publicly sharing the details of a security bug on Twitter, Discord, Telegram, or in public Github issues during the coordination process. | ||
* Once a vulnerability report has been received and triaged: | ||
* Agoric code maintainers will confirm whether it is valid, and will provide updates to the reporter on validity of the report. | ||
* It may take up to 72 hours for an issue to be validated, especially if reported during holidays or on weekends. | ||
* When the Agoric team has verified an issue, remediation steps and patch release timeline information will be shared with the reporter. | ||
* Complexity, severity, impact, and likelihood of exploitation are all vital factors that determine the amount of time required to remediate an issue and distribute a software patch. | ||
* If an issue is Critical or High Severity, Agoric code maintainers will release a security advisory to notify impacted parties to prepare for an emergency patch. | ||
* While the current industry standard for vulnerability coordination resolution is 90 days, Agoric code maintainers will strive to release a patch as quickly as possible. | ||
When a bug patch is included in a software release, the Agoric code maintainers will: | ||
* Confirm the version and date of the software release with the reporter. | ||
* Provide information about the security issue that the software release resolves. | ||
* Credit the bug reporter for discovery by adding thanks in release notes, securing a CVE designation, or adding the researcher’s name to a Hall of Fame. |
@@ -27,2 +27,3 @@ /* global globalThis */ | ||
Math, | ||
Number, | ||
Object, | ||
@@ -29,0 +30,0 @@ Promise, |
@@ -18,2 +18,4 @@ // Copyright (C) 2018 Agoric | ||
import { | ||
FERAL_FUNCTION, | ||
FERAL_EVAL, | ||
TypeError, | ||
@@ -91,2 +93,33 @@ arrayFilter, | ||
const assertDirectEvalAvailable = () => { | ||
let allowed = false; | ||
try { | ||
allowed = FERAL_FUNCTION( | ||
'eval', | ||
'SES_changed', | ||
`\ | ||
eval("SES_changed = true"); | ||
return SES_changed; | ||
`, | ||
)(FERAL_EVAL, false); | ||
// If we get here and SES_changed stayed false, that means the eval was sloppy | ||
// and indirect, which generally creates a new global. | ||
// We are going to throw an exception for failing to initialize SES, but | ||
// good neighbors clean up. | ||
if (!allowed) { | ||
delete globalThis.SES_changed; | ||
} | ||
} catch (_error) { | ||
// We reach here if eval is outright forbidden by a Content Security Policy. | ||
// We allow this for SES usage that delegates the responsibility to isolate | ||
// guest code to production code generation. | ||
allowed = true; | ||
} | ||
if (!allowed) { | ||
throw new TypeError( | ||
`SES cannot initialize unless 'eval' is the original intrinsic 'eval', suitable for direct-eval (dynamically scoped eval) (SES_DIRECT_EVAL)`, | ||
); | ||
} | ||
}; | ||
/** | ||
@@ -179,2 +212,4 @@ * @param {LockdownOptions} [options] | ||
assertDirectEvalAvailable(); | ||
/** | ||
@@ -181,0 +216,0 @@ * Because of packagers and bundlers, etc, multiple invocations of lockdown |
import { | ||
Number, | ||
String, | ||
@@ -36,5 +37,10 @@ TypeError, | ||
}, | ||
toString() { | ||
return `${this}`; | ||
}, | ||
}; | ||
const nonLocaleCompare = tamedMethods.localeCompare; | ||
const numberToString = tamedMethods.toString; | ||
@@ -74,2 +80,8 @@ export default function tameLocaleMethods(intrinsics, localeTaming = 'safe') { | ||
} | ||
// Numbers are special because toString accepts a radix instead of ignoring | ||
// all of the arguments that we would otherwise forward. | ||
defineProperty(Number.prototype, 'toLocaleString', { | ||
value: numberToString, | ||
}); | ||
} |
@@ -291,2 +291,5 @@ /* eslint-disable no-restricted-globals */ | ||
toString: false, | ||
// Superfluously present in some versions of V8. | ||
// https://github.com/tc39/notes/blob/master/meetings/2021-10/oct-26.md#:~:text=However%2C%20Chrome%2093,and%20node%2016.11. | ||
cause: false, | ||
}; | ||
@@ -556,2 +559,5 @@ } | ||
stack: false, | ||
// Superfluously present in some versions of V8. | ||
// https://github.com/tc39/notes/blob/master/meetings/2021-10/oct-26.md#:~:text=However%2C%20Chrome%2093,and%20node%2016.11. | ||
cause: false, | ||
}, | ||
@@ -558,0 +564,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2623008
17
55810
711