Skip to content

Conversation

@btspoony
Copy link
Contributor

No description provided.

- Introduced the @burnt-labs/abstraxion-backend package, including essential files such as package.json, tsconfig.json, and ESLint configuration.
- Set up Jest for testing with a basic configuration.
- Updated pnpm-lock.yaml to reflect new dependencies and versions.
- Added README and CHANGELOG for documentation and version tracking.
… and encryption

- Implemented core functionality for session key management, including storing, retrieving, and revoking session keys.
- Added encryption services using AES-256-GCM for secure session key storage.
- Created a modular architecture with database adapter interfaces for extensibility.
- Introduced comprehensive test coverage for encryption and session key management functionalities.
- Updated README and documentation to reflect new features and usage examples.
- Added validation for configuration parameters in the AbstraxionBackend constructor to ensure required fields are provided.
- Implemented input validation for userId and other parameters in various methods to improve error handling.
- Introduced new error types: UserIdRequiredError and UnknownError for better clarity in error reporting.
- Updated error handling to throw specific errors instead of generic ones, enhancing debugging and user feedback.
- Removed the encryptionService property and its instantiation from the AbstraxionBackend class as it is no longer needed.
- This change simplifies the class structure and improves maintainability.
- Changed Jest test environment from jsdom to node for better compatibility with backend testing.
- Simplified session key generation by directly creating a wallet with a default HD path, removing the previous mnemonic generation method and related code.
- Updated the session key object to reference the wallet's mnemonic directly.
- Reformatted code across multiple files for consistent style, including spacing and line breaks.
- Updated comments to enhance clarity and maintainability.
- Ensured consistent use of double quotes for strings throughout the codebase.
- Improved the structure of import statements for better organization.
- Enhanced readability of function parameters and object properties by aligning them properly.
@changeset-bot
Copy link

changeset-bot bot commented Sep 12, 2025

🦋 Changeset detected

Latest commit: 7e2cda6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@burnt-labs/abstraxion-core Minor
@burnt-labs/tailwind-config Patch
backend-session Patch
demo-app Patch
@burnt-labs/abstraxion-react-native Patch
@burnt-labs/abstraxion Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

… handling improvements

- Integrated node-cache for improved state management with automatic cleanup.
- Added comprehensive error handling with custom error classes for better clarity in error reporting.
- Updated session key management to utilize the new error handling structure.
- Enhanced configuration validation to ensure required fields are provided.
- Introduced new error types for session key operations to improve debugging and user feedback.
- Introduced EncryptionService for AES-256-GCM encryption and decryption of session keys.
- Added SessionKeyManager to manage session key lifecycle, including storage, retrieval, and revocation.
- Updated AbstraxionBackend to utilize the new SessionKeyManager and adjusted import paths accordingly.
- Enhanced test coverage for EncryptionService and SessionKeyManager functionalities.
- Changed import statements for crypto and util modules to use the node: prefix for better clarity and consistency across the codebase.
- Added patch version for @burnt-labs/tailwind-config.
- Updated main and types fields in tailwind-config package.json to point to tailwind.config.ts.
- Removed obsolete .env.example file from abstraxion-backend package.
- Added indexes for username and email in User model for improved query performance.
- Changed sessionKeyExpiry type from Int to DateTime in SessionKey model for better date handling.
- Updated AuditLog model to use DateTime for timestamp and added index for userId and timestamp.
- Modified seed script to use Date objects for timestamps and added sessionKeyAddress in upsert conditions.
- Introduced new methods in database adapter for revoking session keys and managing session key states.
- Enhanced SessionKeyManager to handle session key creation, updates, and revocations more effectively.
- Added comprehensive tests for wallet API and session key management functionalities.
- Introduced new methods for retrieving the last session key and active session keys in the database adapter.
- Updated the session key management logic to utilize the new retrieval methods.
- Refactored session key update and revocation methods to improve clarity and maintainability.
- Adjusted session key info structure to allow optional createdAt and updatedAt fields.
- Improved validation logic for session key info to reflect the updated structure.
- Introduced a comprehensive API middleware system for consistent error handling, rate limiting, and request validation across all API routes.
- Added utility functions for standardized API responses, including success and error formats.
- Created specific wrappers for health check and wallet operations to streamline API handler creation.
- Enhanced type safety and maintainability with TypeScript support and structured context management.
- Updated existing API routes to utilize the new middleware and wrapper functions for improved clarity and functionality.
…thods

- Changed time handling in tests to use Date objects for better clarity and consistency.
- Updated session key revocation method to accept session key address as a parameter.
- Enhanced TestDatabaseAdapter with new methods for retrieving last and active session keys.
- Refactored session key storage and update methods to support multiple session keys per user.
- Improved audit log retrieval to handle Date objects correctly.
- Modified the test description to clarify that it initiates wallet connection for an existing user.
- Added user creation step within the test to ensure the user exists before testing the wallet connection.
- Removed the verification step for user creation as it is now handled within the test setup.
- Updated wallet test to utilize the public sessionKeyManager for better access and clarity.
- Refactored session key management logic to streamline the retrieval of the sessionKeyManager instance.
- Enhanced code readability by removing unnecessary import statements and simplifying the test setup.
- Changed sessionPermissions from an array to an object in multiple test cases for consistency and accuracy in session key management.
- Removed unnecessary imports from SessionKeyManager tests for improved clarity.
- Changed sessionPermissions from an array to an object in TestDatabaseAdapter for consistency in session key management.
- Modified callbackSchema to include 'granted' and 'granter' fields for improved authorization handling.
- Updated AbstraxionBackend to enforce required redirectUrl and treasury parameters.
- Enhanced session key management by storing permissions and granter address during callback processing.
- Refactored error handling to include new errors for missing redirectUrl and granter address.
- Adjusted README to reflect changes in functionality and integration with frontend SDK.
- Added XION_REDIRECT_URL and XION_TREASURY to env.example for improved configuration.
- Updated callbackSchema to include 'state' for better validation.
- Enhanced AbstraxionBackend to validate presence of redirectUrl and treasury during initialization.
- Refactored error handling to utilize centralized error types for consistency.
- Improved session key management by incorporating new parameters in callback processing.
@justinbarry
Copy link
Contributor

@codex

@chatgpt-codex-connector
Copy link

Summary

Testing

  • ⚠️ pnpm --filter backend-session test -- --runTestsByPath src/__tests__/lib/abstraxion-backend/EncryptionService.test.ts (fails: jest binary not available in environment)

View task →

@justinbarry
Copy link
Contributor

image

Can we make this more in line other Xion applications?

user.id,
context.request as any,
);
const signer = await abstraxionAuth.getSigner(
Copy link
Contributor

Choose a reason for hiding this comment

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

You can use the Cosmwasm client here. Hopefully simpler for you.

const client = await abstraxionAuth.getCosmWasmClient()
client.sendTokens(....)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Emmm,
image
ESLint failed, looks like no this method

// Convert amount to micro units
const amountNum = parseFloat(amount);
const microAmount = Math.floor(amountNum * 1_000_000).toString();
const denomMicro = denom === "XION" ? "uxion" : "uusdc";
Copy link
Contributor

@justinbarry justinbarry Oct 23, 2025

Choose a reason for hiding this comment

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

We should really make the usdc IBC denoms a constant someplace.

@btspoony
Copy link
Contributor Author

image Can we make this more in line other Xion applications?

Okay

…Default method to directly return the gas price from xionGasValues
- Changed background colors to black and adjusted text colors to white across various components including HomePage, SignInPage, SignUpPage, ProfilePage, TransferComponent, and WalletComponent.
- Updated loading indicators and error messages to match the new color scheme.
- Enhanced button styles for better visibility and interaction feedback.
@btspoony btspoony requested a review from justinbarry October 28, 2025 13:10
@justinbarry
Copy link
Contributor

@codex Can you review this PR again?

@claude
Copy link

claude bot commented Nov 24, 2025

Pull Request Review: Backend Session Demo Application

Overview

This PR introduces a comprehensive backend session management demo application for XION wallet connections. The implementation includes session key management, encryption, audit logging, and a full-featured API layer with Next.js frontend.


✅ Strengths

1. Security Implementation

  • Strong encryption: AES-256-GCM with proper authentication tags and unique IVs per operation
  • Key derivation: Using scrypt for deriving encryption keys from master key + salt
  • Session key management: Properly encrypted private keys stored in database
  • Rate limiting: Comprehensive rate limiting implementation to prevent abuse
  • Audit logging: Complete audit trail for security events

2. Code Architecture

  • Well-structured error handling: Custom error hierarchy with proper status codes
  • Clean separation of concerns: Service layer, adapters, middleware properly separated
  • Type safety: Comprehensive TypeScript types throughout
  • Database abstraction: Clean adapter pattern for database operations
  • Middleware pattern: Reusable API middleware for common functionality

3. Test Coverage

  • Comprehensive tests: 7 test files covering core functionality
  • Good test organization: Tests for API endpoints, services, and utilities
  • Test database setup: Proper test database isolation

4. Documentation

  • Excellent README: Clear setup instructions, architecture overview, API documentation
  • Setup scripts: Automated setup process with setup.sh
  • Code comments: Well-commented complex logic

🔴 Critical Issues

1. Security: Timing Attack Vulnerability (apps/backend-session/src/lib/xion/security.ts:110-118)

static generateSecureString(
  length: number,
  charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
): string {
  let result = "";
  for (let i = 0; i < length; i++) {
    result += charset.charAt(Math.floor(Math.random() * charset.length));
  }
  return result;
}

Issue: Using Math.random() for security-critical random string generation is not cryptographically secure.

Fix: Replace with cryptographically secure random generation:

static generateSecureString(
  length: number,
  charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
): string {
  const bytes = randomBytes(length);
  let result = "";
  for (let i = 0; i < length; i++) {
    result += charset.charAt(bytes[i] % charset.length);
  }
  return result;
}

2. Security: Sensitive Data Logging (apps/backend-session/src/lib/xion/backend/AbstraxionBackend.ts:370-375)

console.error(
  "Error checking status:",
  error instanceof Error ? error.message : String(error),
);

Issue: Error messages may contain sensitive information (session keys, user IDs) that shouldn't be logged in production.

Recommendation: Implement structured logging with sensitive data redaction.

3. Race Condition Risk (apps/backend-session/src/lib/xion/backend/services/SessionKeyManager.ts:356-379)

const existingSessionKey = await this.databaseAdapter.getSessionKey(
  userId,
  sessionAddress,
);

if (!existingSessionKey) {
  throw new SessionKeyNotFoundError(/*...*/);
}

if (existingSessionKey.sessionState === SessionState.PENDING) {
  await this.databaseAdapter.updateSessionKeyWithParams(/*...*/);
}

Issue: No database transaction wrapping the check-then-update pattern, which could lead to race conditions with concurrent requests.

Recommendation: Use database transactions or implement optimistic locking with version numbers.


⚠️ High Priority Issues

4. Missing Input Validation (apps/backend-session/src/app/api/wallet/transaction/send/route.ts:47-56)

const msgSend: MsgSend = {
  fromAddress: status.metaAccountAddress,
  toAddress: to,
  amount: [/*...*/],
};

Issue: No validation that to address is a valid XION address before creating transaction.

Recommendation: Add address validation:

if (!to.startsWith('xion1') || to.length !== 44) {
  throw new Error('Invalid XION address format');
}

5. Potential Integer Overflow (apps/backend-session/src/app/api/wallet/transaction/send/route.ts:42-43)

const amountNum = parseFloat(amount);
const microAmount = Math.floor(amountNum * 1_000_000).toString();

Issue: No validation for maximum safe integer values. Very large amounts could overflow.

Recommendation: Add validation:

const amountNum = parseFloat(amount);
if (!isFinite(amountNum) || amountNum <= 0 || amountNum > Number.MAX_SAFE_INTEGER / 1_000_000) {
  throw new Error('Invalid amount value');
}

6. Missing Error Recovery (apps/backend-session/src/lib/xion/backend/services/SessionKeyManager.ts:426-450)

private async markAsExpired(sessionKeyInfo: SessionKeyInfo): Promise<void> {
  try {
    await this.databaseAdapter.updateSessionKeyWithParams(/*...*/);
    await this.logAuditEvent(/*...*/);
  } catch (error) {
    console.error("Failed to mark session key as expired:", /*...*/);
  }
}

Issue: Silently swallowing errors could lead to inconsistent state. If marking as expired fails, the app will continue treating an expired key as valid.

Recommendation: At minimum, implement retry logic or dead letter queue for failed state updates.


💛 Medium Priority Issues

7. Inconsistent Error Handling

  • Some methods return null on error (e.g., getLastSessionKeyInfo:68)
  • Others throw exceptions (e.g., getSessionKeypair:106)
  • This inconsistency makes error handling difficult for consumers

Recommendation: Establish consistent error handling patterns across the codebase.

8. Memory Leak Risk (apps/backend-session/src/lib/xion/backend/AbstraxionBackend.ts:52-56)

this._stateStore = new NodeCache({
  stdTTL: 600,
  checkperiod: 60,
  useClones: false,
});

Issue: While NodeCache has TTL, there's no maximum size limit. A DoS attack could fill memory.

Recommendation: Add maxKeys configuration:

this._stateStore = new NodeCache({
  stdTTL: 600,
  checkperiod: 60,
  useClones: false,
  maxKeys: 10000, // Add reasonable limit
});

9. Prisma Schema Index Optimization (apps/backend-session/prisma/schema.prisma:79-84)

@@index([userId, sessionKeyAddress])
@@index([userId, sessionState])
@@index([userId, sessionKeyExpiry])
@@index([userId, metaAccountAddress])
@@index([metaAccountAddress])

Issue: Multiple compound indexes starting with userId may be redundant. Database query optimizer might not use all of them efficiently.

Recommendation: Analyze actual query patterns and consolidate indexes if possible.

10. No Connection Pooling Configuration

The Prisma client is initialized without explicit connection pool configuration. For production use, this should be configured.

Recommendation: Add to schema.prisma:

datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
  connectionLimit = 10
}

💚 Minor Issues / Suggestions

11. Code Duplication

  • Error serialization logic is duplicated across multiple API handlers
  • Audit logging logic could be extracted to a decorator/wrapper

12. Type Safety

// apps/backend-session/src/lib/xion/backend/services/SessionKeyManager.ts:456-459
private async logAuditEvent(
  userId: string,
  action: AuditAction,
  details: Record<string, any>, // <- Using 'any'
)

Recommendation: Define specific types for audit event details instead of Record<string, any>.

13. Missing JSDoc Comments

While code is well-commented, adding JSDoc comments to public methods would improve IDE autocomplete and documentation generation.

14. Environment Variable Validation

The app should validate all required environment variables at startup and fail fast with clear error messages.

Recommendation: Add a startup validation function:

function validateEnv() {
  const required = ['ENCRYPTION_KEY', 'DATABASE_URL', 'XION_RPC_URL', /*...*/];
  const missing = required.filter(key => !process.env[key]);
  if (missing.length > 0) {
    throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
  }
}

15. Test Coverage Gaps

While test coverage is good, the following areas lack tests:

  • Error recovery scenarios
  • Race condition handling
  • Rate limit edge cases
  • Concurrent session key operations

🎯 Performance Considerations

16. Database Query Optimization

The getLastSessionKey method fetches the entire session key record when only checking state might be needed. Consider projection:

// apps/backend-session/src/lib/xion/database.ts:42-45
const sessionKey = await this.prisma.sessionKey.findFirst({
  where: { userId },
  orderBy: { createdAt: "desc" },
  select: { /* only needed fields */ } // Add projection
});

17. Encryption Performance

Scrypt key derivation is intentionally slow for security, but consider caching derived keys per session to avoid repeated expensive operations.


📋 Best Practices

Positive Observations:

✅ Proper use of TypeScript strict mode
✅ Consistent code formatting
✅ Good git commit hygiene with changeset
✅ Environment variable examples provided
✅ Comprehensive README with setup instructions
✅ Proper Next.js 14 App Router usage
✅ Good separation between frontend and backend logic

Areas for Improvement:

⚠️ Add dependency version pinning in package.json (workspace:* is fine for monorepo)
⚠️ Consider adding pre-commit hooks for linting/formatting
⚠️ Add CI/CD configuration for automated testing
⚠️ Consider adding OpenAPI/Swagger documentation for APIs


🏁 Summary

This is a well-architected and comprehensive implementation with strong security foundations. The code demonstrates good understanding of cryptographic principles, proper error handling hierarchy, and clean architectural patterns.

Must Fix Before Merge:

  1. Critical: Replace Math.random() with cryptographically secure random in generateSecureString
  2. Critical: Add database transactions for check-then-update patterns
  3. ⚠️ High: Add input validation for wallet addresses and transaction amounts

Recommended for Follow-up PRs:

  • Implement structured logging with sensitive data redaction
  • Add comprehensive integration tests for race conditions
  • Add environment variable validation at startup
  • Implement connection pooling configuration
  • Add OpenAPI documentation

Test Coverage Assessment:

✅ Good unit test coverage for core services
⚠️ Missing integration tests for concurrent operations
⚠️ Missing e2e tests for complete workflows


Overall Assessment: ⭐⭐⭐⭐☆ (4/5)

This is a strong foundation for a production backend session management system. Address the critical security issues, and this will be production-ready. Excellent work on the architecture and documentation!

🤖 Generated with Claude Code

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 54 to 62
async getSessionKey(
userId: string,
sessionKeyAddress: string,
): Promise<SessionKeyInfo | null> {
const sessionKey = await this.prisma.sessionKey.findUnique({
where: {
userId,
sessionKeyAddress,
},

Choose a reason for hiding this comment

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

P1 Badge Use Prisma unique key when fetching session key

The new Prisma adapter calls findUnique with where: { userId, sessionKeyAddress } even though the Prisma schema only marks sessionKeyAddress as unique (schema.prisma has no @@unique([userId, sessionKeyAddress])). Prisma Client rejects non-unique fields in findUnique/update filters, so any callback/disconnect path that hits getSessionKey (and the similar revoke/update methods) will throw a runtime validation error before reaching the database. Consider querying by the actual unique key or adding a compound unique constraint.

Useful? React with 👍 / 👎.

Copy link
Contributor

Choose a reason for hiding this comment

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

@codex How can we test if this is the case?

Choose a reason for hiding this comment

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

Summary

Testing

  • ⚠️ pnpm --filter backend-session test -- --runTestsByPath apps/backend-session/src/__tests__/lib/database.test.ts (fails: jest not available in environment)

View task →

- add unit tests for PrismaDatabaseAdapter methods
- Introduced comprehensive tests for session key management functions including getSessionKey, revokeSessionKey, and updateSessionKeyWithParams.
- Implemented setup and teardown for a test database using Prisma.
- Validated session key retrieval, revocation, and updates with user ID checks to ensure proper access control.
- Enhanced error handling and cleanup processes in the test suite.
@claude
Copy link

claude bot commented Nov 25, 2025

Code Review - PR #308: Backend Adaptation Demo

Thank you for this comprehensive PR adding the abstraxion-backend package and demo application! This is a substantial addition with well-structured code. I've conducted a thorough review focusing on code quality, security, performance, bugs, and test coverage.

Overall Assessment

Strengths:

  • Excellent TypeScript usage with strong typing throughout
  • Clean architecture with clear separation of concerns (services, adapters, strategies)
  • Comprehensive custom error handling
  • Good test foundation with 8 test suites
  • Well-documented README files

Concerns: Several security and correctness issues need attention before production use.


Critical Issues (Must Fix Before Merge)

1. Encryption Service - Improper AAD Usage

File: packages/abstraxion-backend/src/services/EncryptionService.ts:39

cipher.setAAD(salt);

Issue: Using salt as Additional Authenticated Data (AAD) in GCM mode is cryptographically incorrect. AAD should be public metadata (like user ID), not cryptographic material like salt.

Recommendation: Remove AAD usage or use proper authenticated data:

// Option 1: Remove AAD entirely
// cipher.setAAD(salt); // Remove this line

// Option 2: Use proper AAD (public metadata)
const aad = Buffer.from(`userId:${userId}:purpose:sessionKey`);
cipher.setAAD(aad);

2. Validation Type Mismatch

File: packages/abstraxion-backend/src/validation.ts:28-32, 34

if (
  typeof sessionKeyInfo.sessionKeyExpiry !== "number" ||
  sessionKeyInfo.sessionKeyExpiry <= 0
)

if (!Array.isArray(sessionKeyInfo.sessionPermissions)) {
  return false;
}

Issue:

  • sessionKeyExpiry is a Date object (per database.ts:30), not a number
  • sessionPermissions is a Permissions object, not an array

Recommendation:

if (
  !(sessionKeyInfo.sessionKeyExpiry instanceof Date) ||
  isNaN(sessionKeyInfo.sessionKeyExpiry.getTime())
)

if (typeof sessionKeyInfo.sessionPermissions !== 'object' || 
    sessionKeyInfo.sessionPermissions === null) {
  return false;
}

3. Race Condition in Session Key Refresh

File: packages/abstraxion-backend/src/services/SessionKeyManager.ts:239-248

Issue: Multiple concurrent requests can trigger simultaneous session key refreshes, creating multiple pending keys.

Recommendation: Add check for existing pending keys:

// Check if refresh already in progress
const existingPending = await this.databaseAdapter.getLastSessionKeyInfo(userId);
if (existingPending?.sessionState === SessionState.PENDING) {
  return existingPending;
}

const timeUntilExpiry = sessionKeyInfo.sessionKeyExpiry.getTime() - Date.now();
if (timeUntilExpiry <= this.refreshThresholdMs) {
  const newSessionKey = await this.generateSessionKeypair();
  await this.createPendingSessionKey(userId, newSessionKey);
  return newSessionKey;
}

4. Information Disclosure in Error Messages

File: packages/abstraxion-backend/src/AbstraxionBackend.ts:375-378

const sanitizedMessage = errorMessage
  .replace(/sessionKey[^,\s]*/gi, "[REDACTED]")
  .replace(/userId[^,\s]*/gi, "[REDACTED]")
  .replace(/address[^,\s]*/gi, "[REDACTED]");

Issue: Regex patterns too simple - can be bypassed by variations like "sessionKey_material", "sessionkey2", etc.

Recommendation: Use more robust patterns or whitelist approach:

const sanitizedMessage = errorMessage
  .replace(/sessionKey\w*/gi, "[REDACTED]")
  .replace(/userId[\w]*/gi, "[REDACTED]")
  .replace(/address[\w]*/gi, "[REDACTED]")
  .replace(/xion1[a-z0-9]{38,}/gi, "[ADDRESS_REDACTED]") // Bech32 addresses
  .replace(/0x[a-fA-F0-9]{64,}/gi, "[KEY_REDACTED]"); // Hex keys

High Priority Issues (Should Fix)

5. Weak Random String Generation

File: apps/backend-session/src/lib/xion/security.ts:113-120

Issue: Modulo bias in random generation: bytes[i] % charset.length introduces statistical bias.

Recommendation:

static generateSecureString(length: number, charset = "..."): string {
  let result = "";
  const charsetLength = charset.length;
  
  for (let i = 0; i < length; i++) {
    // Use rejection sampling to avoid bias
    let randomValue;
    do {
      randomValue = randomBytes(1)[0];
    } while (randomValue >= 256 - (256 % charsetLength));
    
    result += charset.charAt(randomValue % charsetLength);
  }
  return result;
}

6. State Cleanup Incomplete

File: packages/abstraxion-backend/src/AbstraxionBackend.ts:164-171

Issue: When authorization is denied, state is cleaned but pending session key remains in database.

Recommendation:

if (!request.granted) {
  this._stateStore.del(request.state);
  
  // Also clean up pending session key
  try {
    const lastKey = await this.sessionKeyManager.getLastSessionKeyInfo(userId);
    if (lastKey?.sessionState === SessionState.PENDING) {
      await this.sessionKeyManager.revokeSessionKey(userId, lastKey.sessionKeyAddress);
    }
  } catch (err) {
    this.logError("Failed to cleanup pending session key", err);
  }
  
  return { success: false, error: "Authorization was not granted by user" };
}

7. Floating-Point Financial Calculations

File: apps/backend-session/src/app/api/transaction/send/route.ts:48-56

Issue: Using floating-point arithmetic for financial amounts risks precision loss.

Recommendation: Use integer-only arithmetic or decimal library:

// Option 1: String-based conversion
const [whole, decimal = ""] = amount.split(".");
const paddedDecimal = decimal.padEnd(6, "0").slice(0, 6);
const microAmount = whole + paddedDecimal;

// Option 2: Use decimal.js
import Decimal from "decimal.js";
const microAmount = new Decimal(amount).mul(1_000_000).floor().toString();

8. Missing CSRF Protection on Callback

File: apps/backend-session/src/app/api/callback/grant_session/route.ts

Issue: Callback endpoint lacks CSRF protection beyond state parameter.

Recommendation: Add origin/referer validation:

// Validate request origin
const origin = request.headers.get("origin");
const expectedOrigin = process.env.XION_DASHBOARD_URL;
if (origin && origin !== expectedOrigin) {
  return apiError("Invalid request origin", 403);
}

9. Database Connection Pool Not Configured

File: apps/backend-session/src/lib/xion/database.ts:15-19

Issue: PrismaClient created without explicit connection pool configuration.

Recommendation:

const prisma = new PrismaClient({
  datasources: {
    db: {
      url: process.env.DATABASE_URL,
    },
  },
  // Add connection pool configuration
  pool: {
    max: 10,
    min: 2,
    idleTimeoutMillis: 30000,
  },
});

10. Rate Limiting Header Spoofing

File: apps/backend-session/src/lib/api-response.ts:126-143

Issue: IP extraction from x-forwarded-for header can be spoofed if not behind trusted proxy.

Recommendation: Add configuration option:

function getClientIp(request: NextRequest): string {
  const trustProxy = process.env.TRUST_PROXY === "true";
  
  if (trustProxy) {
    const forwarded = request.headers.get("x-forwarded-for");
    if (forwarded) {
      return forwarded.split(",")[0].trim();
    }
  }
  
  // Fallback to direct connection
  return request.ip || "unknown";
}

Medium Priority Issues (Consider Fixing)

11. Type Safety Violation

File: packages/abstraxion-backend/src/services/SessionKeyManager.ts:358-373

const adapter = this.databaseAdapter as any;

Recommendation: Use proper type guard:

interface ExtendedDatabaseAdapter extends DatabaseAdapter {
  updateSessionKeyWithParamsAtomic?: (params: UpdateParams) => Promise<void>;
}

const adapter = this.databaseAdapter as ExtendedDatabaseAdapter;
if (adapter.updateSessionKeyWithParamsAtomic) {
  await adapter.updateSessionKeyWithParamsAtomic({...});
}

12. N+1 Query Pattern

File: packages/abstraxion-backend/src/services/SessionKeyManager.ts:199-207

Recommendation: Batch audit log insertions:

const auditEntries = activeSessionKeys.map(key => ({
  userId,
  action: AuditAction.SESSION_KEY_REVOKED,
  details: { sessionKeyAddress: key.sessionKeyAddress }
}));

await this.databaseAdapter.createAuditLogs(auditEntries); // Add batch method
await this.databaseAdapter.revokeActiveSessionKeys(userId);

13. Inconsistent Password Hashing

File: apps/backend-session/src/lib/xion/security.ts:72-78 vs usage of bcrypt elsewhere

Recommendation: Standardize on bcrypt throughout:

// Remove PBKDF2 implementation, use bcrypt everywhere
import bcrypt from 'bcryptjs';

static async hashPassword(password: string): Promise<string> {
  return bcrypt.hash(password, 12);
}

static async verifyPassword(password: string, hash: string): Promise<boolean> {
  return bcrypt.compare(password, hash);
}

14. NodeCache Memory Concerns

File: packages/abstraxion-backend/src/AbstraxionBackend.ts:52-56

Recommendation: Add memory limit:

this._stateStore = new NodeCache({
  stdTTL: 600,
  checkperiod: 60,
  useClones: false,
  maxKeys: 1000, // Reduced from 10000
  deleteOnExpire: true,
});

15. Raw SQL Usage

File: apps/backend-session/src/lib/xion/database.ts:306

await this.prisma.$queryRaw`SELECT 1`;

Recommendation: Use Prisma's built-in method:

// Better health check
await this.prisma.$connect();

Test Coverage Gaps

Missing Tests:

  1. API Integration Tests - Only wallet.test.ts exists. Need tests for:

    • /api/callback/grant_session
    • /api/wallet/disconnect
    • /api/wallet/status
    • /api/health
    • Authentication endpoints
  2. Concurrent Request Tests - No testing of race conditions or concurrent operations

  3. Error Propagation Tests - Custom error classes not comprehensively tested

  4. Rate Limiting Edge Cases - Limit reset, multiple IPs, distributed scenarios

Recommendation: Add comprehensive integration test suite before production deployment.


Documentation Improvements

  1. Add Security Documentation

    • Document security assumptions (requires HTTPS, trusted reverse proxy, etc.)
    • Add threat model documentation
    • Document key rotation procedures
  2. Add JSDoc Comments

    • Public APIs need usage examples
    • Document parameter constraints
  3. Deployment Guide

    • Production configuration checklist
    • Database backup strategy
    • Monitoring recommendations

Minor Issues / Nits

  • Remove deprecated function createOrGetUser (api-wrapper.ts:165)
  • Add timeout to pollForGrants (AbstraxionBackend.ts:199)
  • Consider structured logging instead of console.log/error
  • Add request ID tracking for debugging
  • Document the intentional bypass in addNewSessionKey allowing direct ACTIVE state

Summary

This is a well-architected implementation with solid fundamentals. The critical issues are primarily around:

  1. Cryptographic correctness
  2. Type safety
  3. Race conditions
  4. Information leakage

Once the critical and high-priority issues are addressed, this will be a robust backend solution for session management.

Recommendation: Please address the 4 critical issues and at least issues #5-10 from high priority before merging. The remaining items can be tracked as follow-up work.

Great work overall! Happy to discuss any of these findings.

…n session key management

- Improved error message redaction with more robust patterns to protect sensitive information.
- Added a check in SessionKeyManager to return an existing pending session key instead of creating a new one, preventing potential race conditions.
- Removed outdated validation functions from the validation utility file to streamline the codebase.
@claude
Copy link

claude bot commented Nov 25, 2025

PR Review: Backend Session Demo Implementation

Overview

Comprehensive PR adding backend session management demo with ~20K lines across 74 files.

Strengths

  • Well-structured architecture with clear separation of concerns
  • Comprehensive error handling with custom error classes
  • Strong TypeScript typing throughout
  • Detailed README and good test coverage (8 test files)

Critical Issues to Fix Before Merge

1. Race Condition (HIGH)

Location: SessionKeyManager.ts:392-429
Issue: Fallback path has race condition between read and update
Fix: Remove fallback or enforce atomic updates only

2. Database Security Issue (HIGH)

Location: database.ts:68-71
Issue: getSessionKey checks userId after fetch, could leak key existence
Fix: Include userId in WHERE: where: { sessionKeyAddress, userId }

3. Type Safety Bypass (MEDIUM)

Location: SessionKeyManager.ts:369
Issue: Uses 'as any' type assertion
Fix: Add proper type checking or use type guards

4. Hardcoded Test Password (SECURITY)

Location: prisma/seed.ts:10
Issue: Uses "password123" for test users
Fix: Generate random passwords even for test data

Security Concerns

  • Rate Limiting: Memory-based, resets on restart. Consider Redis for production
  • Key Rotation: Missing documentation on encryption key rotation strategy
  • Auth Inconsistency: Uses both bcryptjs and custom PBKDF2. Should standardize
  • Logging: Uses console.error in production code. Need proper logging service

Performance Considerations

  • Encryption: scrypt key derivation on every encrypt/decrypt. Consider caching
  • NodeCache: Max 10k keys without memory limit could cause OOM
  • Database: getActiveSessionKeys could be slow. Add pagination
  • Indexes: Consider composite index on (userId, sessionState, sessionKeyExpiry)

Test Coverage Gaps

  • Encryption failures and corrupted data scenarios
  • Database connection failures during critical ops
  • Rate limiting concurrent request edge cases
  • End-to-end callback flow integration tests
  • Key rotation and concurrent update scenarios

Code Consistency

  • Inconsistent error handling patterns (re-throw vs wrap)
  • Mixed async patterns (try/catch vs .catch chains)
  • Missing architecture documentation and error code docs

Recommendations

Must Fix Before Merge

  1. Fix race condition in session key updates
  2. Fix database query security issue
  3. Remove type safety bypass
  4. Change hardcoded test password

Should Fix Soon

  1. Standardize on bcrypt/argon2
  2. Implement proper logging service
  3. Add NodeCache memory limits
  4. Document error codes

Nice to Have

  1. More integration tests
  2. Redis-backed rate limiting
  3. Architecture documentation
  4. Performance monitoring

Final Verdict

High-quality implementation with strong foundations. Architecture is sound and code is well-tested. Please address the 4 critical issues above before merge. After fixes, ready to merge!

Great work overall! 🎉


Review generated with Claude Code

- Introduced helper functions for user creation and database cleanup to streamline test setup.
- Updated wallet API tests to utilize the new helper functions, enhancing readability and maintainability.
- Ensured proper user existence checks before session key creation in the database adapter.
- Improved error handling in session key management to prevent operations on non-existent users.
@claude
Copy link

claude bot commented Nov 25, 2025

PR Review: Backend Adaptation Demo

Overview

This PR introduces a comprehensive backend session management demo application for XION wallet connections with ~19,685 additions across 74 files. The implementation includes a new Next.js app with session key management, encryption, database integration, and extensive test coverage.


✅ Strengths

Architecture & Design

  • Well-structured layering: Clear separation between API routes, business logic (AbstraxionBackend), and data access (DatabaseAdapter)
  • Comprehensive error handling: Custom error hierarchy with typed errors
  • Strategy pattern: Clean implementation of storage and redirect strategies
  • State management: Smart use of node-cache with automatic TTL and cleanup

Security Implementation

  • Strong encryption: AES-256-GCM with proper key derivation using scrypt
  • Auth tag verification: GCM mode provides authenticated encryption
  • Unique IVs & salts: Each encryption operation uses cryptographically random values
  • Rate limiting: Implemented with configurable strict/normal modes
  • Audit logging: Comprehensive tracking of security events
  • Constant-time comparison: Prevents timing attacks

Code Quality

  • TypeScript throughout: Strong typing with proper interfaces
  • Validation: Zod schemas for input validation
  • Middleware pattern: Reusable API middleware
  • Comprehensive tests: 8 test files covering core functionality

🔴 Critical Issues

1. Race Condition in Session Key Updates

Location: SessionKeyManager.ts:368-427

The code implements atomic updates for Prisma but falls back to non-atomic updates for other adapters, creating a check-then-update race condition window.

Impact: Multiple simultaneous callbacks could update the same session key.

Recommendation: Either require atomic operations or implement distributed locking.

2. Missing Input Validation on Transaction Amount

Location: route.ts:48-56

  • parseFloat accepts scientific notation
  • Math.floor could lead to precision loss
  • No validation against user permission limits

Recommendation: Add regex validation for decimal format and check against permission limits.

3. Error Message Information Disclosure

Location: AbstraxionBackend.ts:373-381

Regex-based sanitization may not catch all variations. Server logs could capture sensitive data.

Recommendation: Use structured logging with automatic PII redaction.


🟡 Bugs & Issues

4. Session Key Expiry Check Inconsistency

PENDING keys can expire but aren't checked. Keys never activated remain in limbo.

Recommendation: Add expiry check for PENDING state and implement cleanup job.

5. Cache Size Limit

10,000 max states with 10-min TTL = ~1,000 attempts/min max. Under load, legitimate requests could be denied.

Recommendation: Add monitoring, consider Redis for production.

6. Encryption Key Validation

Only checks length, not cryptographic strength.

Recommendation: Add entropy validation.


🟠 Performance Considerations

7. N+1 Queries in Audit Logging

Each operation logs individually without batching.

Recommendation: Implement batch audit logging.

8. Encryption in Hot Path

Every getSessionKeypair call decrypts synchronously.

Recommendation: Consider short-lived caching.

9. Missing Database Indexes

Add compound index on (userId, sessionState, sessionKeyExpiry) for common queries.


✅ Test Coverage

Excellent coverage with 8 comprehensive test files covering API endpoints, encryption, session management, database operations, rate limiting, and security utilities.

Missing tests: Integration tests for full OAuth flow, load testing, concurrency tests.


📋 Additional Recommendations

  • Add architecture and sequence diagrams
  • Implement environment variable validation at startup
  • Add monitoring and observability metrics
  • Extract magic numbers to constants
  • Document gas price default behavior

🎯 Summary

Well-architected backend session management system with strong security foundations, high code quality, and excellent test coverage.

Must Fix Before Merge:

  1. Race condition in non-atomic database updates
  2. Transaction amount validation and permission checking
  3. Error message sanitization strategy

Should Fix Soon:
4. PENDING state expiry handling
5. Cache monitoring/scaling strategy
6. Compound database indexes

Verdict: Approve with required changes. Foundation is solid for production with noted fixes.

Great work on security details and comprehensive testing! 🎉

@btspoony
Copy link
Contributor Author

Created a separated demo repo for this usage:
https://github.com/burnt-labs/xion-backend-session-demo

@btspoony btspoony closed this Nov 28, 2025
@btspoony btspoony deleted the backend-adaption branch November 28, 2025 15:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants