Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased (develop)

- added: Changelly plugin info revised
- added: Logbox disable option to env.json
- added: Reverse-resolve recipient addresses to ENS / Unstoppable Domains / ZNS names in the send flow, address modal, and transaction history.

Expand Down
16 changes: 16 additions & 0 deletions scripts/obfuscateString.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Generates the obfuscated char-code array to paste into env.json for
// fields cleaned by asObfuscatedString.
//
// Usage:
// node -r sucrase/register scripts/obfuscateString.ts <plaintext...>

import { wasObfuscatedString } from '../src/util/cleaners/asObfuscatedString'

const plaintext = process.argv.slice(2).join(' ')

if (plaintext === '') {
console.error('Usage: obfuscateString.ts <plaintext>')
process.exit(1)
}

console.log(JSON.stringify(wasObfuscatedString(plaintext)))
1 change: 1 addition & 0 deletions src/actions/CategoriesActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,7 @@ export const pluginIdIcons: Record<string, string> = {
bridgeless: EDGE_CONTENT_SERVER_URI + '/bridgeless.png',
changenow: EDGE_CONTENT_SERVER_URI + '/changenow.png',
changehero: EDGE_CONTENT_SERVER_URI + '/changehero.png',
changelly: EDGE_CONTENT_SERVER_URI + '/changelly.png',
cosmosibc: EDGE_CONTENT_SERVER_URI + '/cosmosibc.png',
exolix: EDGE_CONTENT_SERVER_URI + '/exolix-logo.png',
fantomsonicupgrade: EDGE_CONTENT_SERVER_URI + '/fantomsonicupgrade.png',
Expand Down
5 changes: 5 additions & 0 deletions src/components/modals/SwapVerifyTermsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ const pluginData: Record<string, TermsUri> = {
privacyUri: 'https://changenow.io/privacy-policy',
kycUri: 'https://changenow.io/faq/kyc'
},
changelly: {
termsUri: 'https://changelly.com/terms-of-use',
privacyUri: 'https://changelly.com/privacy-policy',
kycUri: 'https://changelly.com/aml-kyc'
},
exolix: {
termsUri: 'https://exolix.com/terms',
privacyUri: 'https://exolix.com/privacy',
Expand Down
8 changes: 8 additions & 0 deletions src/envConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { asInitOptions as asPaybisInitOptions } from './plugins/ramps/paybis/pay
import { asInitOptions as asRevolutInitOptions } from './plugins/ramps/revolut/revolutRampTypes'
import { asInitOptions as asSimplexInitOptions } from './plugins/ramps/simplex/simplexRampTypes'
import { asBase16 } from './util/cleaners/asHex'
import { asObfuscatedString } from './util/cleaners/asObfuscatedString'

function asNullable<T>(cleaner: Cleaner<T>): Cleaner<T | null> {
return function asNullable(raw) {
Expand Down Expand Up @@ -266,6 +267,13 @@ export const asEnvConfig = asObject({
apiKey: asOptional(asString, '')
}).withRest
),
CHANGELLY_INIT: asCorePluginInit(
asObject({
// Arrays of XOR-masked char codes; see asObfuscatedString.
apiKey: asOptional(asObfuscatedString, ''),
secret: asOptional(asObfuscatedString, '')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Agentic Security Review
Severity: HIGH

CHANGELLY_INIT.secret is being accepted as an XOR-obfuscated client value (asObfuscatedString). This is reversible by anyone with app/bundle access, so it does not protect a partner API secret and effectively ships the secret to end users.

Impact: The exposed credential can be extracted and reused for unauthorized Changelly API usage (quota/billing abuse and integration impersonation).

Fix in Cursor Fix in Web

Reviewed by Cursor Security Reviewer for commit b4e9343. Configure here.

}).withRest
),
COREUM_INIT: asCorePluginInit(asBoolean),
COSMOSHUB_INIT: asCorePluginInit(asBoolean),
DASH_INIT: asCorePluginInit(
Expand Down
19 changes: 19 additions & 0 deletions src/util/cleaners/asObfuscatedString.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { asArray, asCodec, asNumber, uncleaner } from 'cleaners'

// XOR mask applied to each char code. Not a secret.
const MASK = 0x5a

/**
* Decodes a string stored as an array of XOR-masked char codes,
* e.g. "hi" <-> [0x32, 0x33]. Use `wasObfuscatedString` or
* scripts/obfuscateString.ts to generate the array.
*/
export const asObfuscatedString = asCodec<string>(
raw =>
asArray(asNumber)(raw)
.map(code => String.fromCharCode(code ^ MASK))
.join(''),
clean => clean.split('').map(ch => ch.charCodeAt(0) ^ MASK)
)

export const wasObfuscatedString = uncleaner(asObfuscatedString)
1 change: 1 addition & 0 deletions src/util/corePlugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export const swapPlugins = {
// Centralized Swaps
changehero: ENV.CHANGEHERO_INIT,
changenow: ENV.CHANGE_NOW_INIT,
changelly: ENV.CHANGELLY_INIT,
exolix: ENV.EXOLIX_INIT,
godex: ENV.GODEX_INIT,
lifi: ENV.LIFI_INIT,
Expand Down
Loading