Skip to content

Commit d72a579

Browse files
committed
ERC-7754: adding key security detail to the TWIST verification spec
Signed-off-by: Guillaume Grosbois <[email protected]>
1 parent 9857889 commit d72a579

File tree

1 file changed

+18
-3
lines changed

1 file changed

+18
-3
lines changed

ERCS/erc-7754.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,12 @@ const result = await ethereum.request({
156156
#### Signature verification
157157

158158
1. Upon receiving an [EIP-1193](./eip-1193.md) call, the wallet MUST check of the existence of the TWIST manifest for the `sender.tab.url` domain
159-
a. The wallet MUST verify that the manifest is hosted on the `sender.tab.url` domain
160-
b. The wallet SHOULD find the DNS TXT record to find the manifest location
161-
b. The wallet MAY first try the `/.well-known/twist.json` location
159+
a. The wallet MUST enforce HTTPS as HTTP call would be vulnerable to DNS spoofing
160+
b. The wallet MUST verify that the manifest is hosted on the `sender.tab.url` domain
161+
c. The wallet SHOULD find the DNS TXT record to find the manifest location
162+
d. The wallet MAY first try the `/.well-known/twist.json` location
163+
e. The wallet MUST NOT follow redirects when querying the manifest location as it could lead to open redirect attacks
164+
f. The wallet SHOULD validate the `Content-Type` header of the response is specifically set to `application/json`
162165
2. If TWIST is NOT configured for the `sender.tab.url` domain, then proceed as usual
163166
3. If TWIST is configured and the `request` method is used, then the wallet SHOULD display a visible and actionable warning to the user
164167
a. If the user opts to ignore the warning, then proceed as usual
@@ -201,6 +204,9 @@ async function signedRequest(
201204

202205
// 3. Parse the manifest and get the key and algo based on `keyId`
203206
const manifestReq = await fetch(manifestPath);
207+
if(manifestReq.headers['content-type']!=='application/json'){
208+
throw new Error('The manifest is not a proper json file')
209+
}
204210
const manifest = await manifestReq.json();
205211
const keyData = manifest.publicKeys.filter((x) => x.id == keyId);
206212
if (!keyData) {
@@ -251,6 +257,15 @@ which are of very limited value for an attacker.
251257
For these reason, we do not recommend a specific replay protection mechanism at this time. If/when the need arise, the extensibility of
252258
the manifest will provide the necessary room to enforce a replay protection envelope (eg:JWT) for affected dapp.
253259

260+
### Malicious manifests
261+
262+
The manifest itself could be attacked, defeating the purpose of TWIST. We identified the following possible attacks, and their counter measure:
263+
264+
1. An attacker can spoof DNS entries and use it to serve their own manifest: to avoid this, the wallet implementation MUST only query the manifest from `'https://' + sender.tab.url + '/' + pathFromDNSRecord
265+
2. An attacker can leverage other flaws in a dapp to host a malicious manifest on the dapp domain itself
266+
a. by leveraging open redirect: consequently the wallet MUST NOT follow redirect when querying the manifest
267+
b. by managing to host a file on the dapp domain: consequently the wallet SHOULD verify the `content-type` header is equal to `application/json` to mitigate this attack vector
268+
254269
## Copyright
255270

256271
Copyright and related rights waived via [CC0](../LICENSE.md).

0 commit comments

Comments
 (0)