CVE-2019-16281 (TypeScript, published 2020-12-30T21:15Z)
Description: value: Ptarmigan before 0.2.3 lacks API token validation, e.g., an "if (token === apiToken) {return true;} return false;" code block.
Severity: MEDIUM (CVSS v3 base score: 7.5)
Weakness: CWE-295 \u2014 Improper Certificate Validation
The product does not validate, or incorrectly validates, a certificate.
Repository: https://github.com/nayutaco/ptarmigan
Files changed:
ptarmapi/.env-sample
ptarmapi/package.json
ptarmapi/script/addfinal.sh
ptarmapi/script/htlcchanged.sh
ptarmapi/src/app.module.ts
ptarmapi/src/auth/auth.module.ts
ptarmapi/src/auth/auth.service.ts
ptarmapi/src/auth/http.strategy.ts
ptarmapi/src/config/ptarmigan.ts
ptarmapi/src/main.ts
ptarmapi/src/notifications/invoices.gateway.ts
ptarmapi/src/ptarmigan/ptarmigan.controller.ts
ptarmapi/test/client/index.html
Commit message: add api token in rest api

add apiBeareAuth

add token in .env-sample


Vulnerable code:
}
 --verbose
 --verbose

import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { Logger } from '@nestjs/common';
import { Controller, Get, Patch, Put, Param, Post, Body, Delete, Logger, Query, Next } from '@nestjs/common';
import { ApiUseTags, ApiModelProperty, ApiImplicitQuery, ApiCreatedResponse, ApiForbiddenResponse } from '@nestjs/swagger';
        private readonly invoicesGateway: InvoicesGateway

            return 'error';
            return 'error';
    const url = 'ws://127.0.0.1:3001/ws';

Fixed code:
API_TOKEN="ptarmigan"
    "@nestjs/passport": "^6.1.0",
    "passport": "^0.4.0",
    "passport-http-bearer": "^1.0.1",
}
if [ "${API_TOKEN:-unknown}" == unknown ]; then
  API_TOKEN=ptarmigan
fi

 --header "Authorization: Bearer $API_TOKEN"
if [ "${API_TOKEN:-unknown}" == unknown ]; then
  API_TOKEN=ptarmigan
fi

 --header "Authorization: Bearer $API_TOKEN"
import { AuthModule } from './auth/auth.module';
    AuthModule,
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { HttpStrategy } from './http.strategy';
import { PassportModule } from '@nestjs/passport';

@Module({
 imports: [
  PassportModule.register({ defaultStrategy: 'bearer' }),
 ],
 providers: [AuthService, HttpStrategy],
 exports: [PassportModule, AuthService],
})
export class AuthModule {}
import { Injectable } from '@nestjs/common';
import { ConfigService } from 'nestjs-config';

@Injectable()
export class AuthService {

  constructor() { }

  async validateApiToken(token: string): Promise<any> {
    const apiToken = ConfigService.get('ptarmigan.apiToken');
    if (token === apiToken) {
      return true;
    }
    return false;
  }
}
import { Strategy } from 'passport-http-bearer';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';

@Injectable()
export class HttpStrategy extends PassportStrategy(Strategy) {
  constructor(private readonly authService: AuthService) {
    super();
  }

  async validate(token: string) {
    const apiToken = await this.authService.validateApiToken(token);
    if (!apiToken) {
      throw new UnauthorizedException();
    }
    return apiToken;
  }
}
    apiToken: process.env.API_TOKEN || 'ptarmigan',
import { SwaggerModule, DocumentBuilder, SwaggerBaseConfig } from '@nestjs/swagger';
    .addBearerAuth('Authorization', 'header')
  Logger.log('bitcoindHost: ' + config.get('ptarmigan.apiToken'));
import { Logger, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
    @UseGuards(AuthGuard())
import { Controller, Get, Patch, Put, Param, Post, Body, Delete, Logger, Query, Next, UseGuards } from '@nestjs/common';
import { ApiUseTags, ApiModelProperty, ApiImplicitQuery, ApiCreatedResponse, ApiForbiddenResponse, ApiBearerAuth } from '@nestjs/swagger';
import { AuthGuard } from '@nestjs/passport';
        private readonly invoicesGateway: InvoicesGateway,
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())

    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
   
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
            return error;
    @ApiBearerAuth()
    @UseGuards(AuthGuard())
            return error;
    const url = 'ws://127.0.0.1:3000/ws';