OWASP Juice Shop

Achieving sustainability for open source projects


Presentation by Bjรถrn Kimminich / @bkimminich

Chapter One


OWASP Juice Shop...

...is an intentionally insecure webapp written in Node.js, Express and AngularJS. It contains 38+ hacking challenges of varying difficulty tracked on a score board.

Modern Web-Architecture

Javascript all the way from UI to REST API

OWASP Juice Shop CTF...

...is a commandline tool written in Node.js and published on NPM.js. It helps you to set up and host CTF events on the CTFd platform with the Juice Shop challenges.

<!-- uncomment this and the following slide **ONLY** if...

------------------------------------------------- -->

<!-- ...Juice Shop got promoted to  Lab  Project 

during the Project Summit prior to this AppSecEU! :-D

The next OWASP Connector should make this official! (But you heard it here first!)

------------------------------------------------- -->

Chapter Two

Open Source Antipatterns


An empty or lackluster front-page radiates the impression that nobody takes serious care of the project.

Bad Example

Worse Example

Worst Example

Good Example

Better(?) Example

Pile of Issues

Open issues pile up in the ticketing system, most of them unanswered and unattended.

A pile of unattended issues


Really a ๐Ÿ’ฉ-pile of unattended issues

Counter: Use  labels  properly

Agile Counter: Kanban Board


PR Disaster

Pull Requests are routinely ignored or flogged to death.

Ignored Pull Requests


Example for a PR flogged to death*

*Disclaimer: This example should by no means imply that the ZAP team is routinely flogging PRs to death! On the contrary, they offer a helping hand to even those who totally ignore their written contribution requirements!

Good Counter: Contribution Guide (ZAP)


Contribution Guide (Juice Shop)


Auto Counter: ๐Ÿ‘Š-enforced Coding Style


Solecistic Versioning

The Semantic Versioning syntax (MAJOR.MINOR.PATCH) is used while its semantics are not adhered to.

Bad Example: AngularJS 1.x

Good Example: AngularJS 2+

Juice Shop takes it serious

For a tiny incompatible configuration-file change Juice Shop went from 2.26.0 to 3.0.0

Major Zero

Not even the original author thinks that the project is mature enough to release a 1.x version from it.

Example: z85-cli๐Ÿ˜œ

Chapter Three

My little OSS Sustainability Toolbox

Git Flow

The master branch stores the official release history, while development happens on the develop branch.

Git Flow โ’ Feature Branches

Clean Code

Clean Javascript! ๐Ÿ˜ฎ

'use strict'

var path = require('path')
var utils = require('../lib/utils')
var challenges = require('../data/datacache').challenges

exports = module.exports = function servePremiumContent () {
  return function (req, res) {
    if (utils.notSolved(challenges.premiumPaywallChallenge)) {
    res.sendFile(path.resolve(__dirname, '../app/private/under-construction.gif'))

Well, never mind...

fs.copy('app/index.template.html', 'app/index.html', {overwrite: true}, function () {
      if (config.get('application.logo')) {
        var logo = config.get('application.logo')
        if (utils.startsWith(logo, 'http')) {
          var logoPath = logo
          logo = decodeURIComponent(logo.substring(logo.lastIndexOf('/') + 1))
          utils.downloadToFile(logoPath, 'app/public/images/' + logo)
        var logoImageTag = ''
        replace({ regex: //, replacement: logoImageTag, paths: ['app/index.html'], recursive: false, silent: true })
      if (config.get('application.theme')) {
        var themeCss = 'bower_components/bootswatch/' + config.get('application.theme') + '/bootstrap.min.css'
        replace({ regex: /bower_components\/bootswatch\/.*\/bootstrap\.min\.css/, replacement: themeCss, paths: ['app/index.html'], recursive: false, silent: true })

...it's still Javascript at the end of the day! ๐Ÿค

Test Automation

Example: UI Unit Test

it('should hold anonymous placeholder for email if current user is not logged in',
  inject(function () {
      $httpBackend.whenGET('/rest/user/whoami').respond(200, {user: {}})



Example: API Integration Test

frisby.create('GET password change without passing any passwords')
  .get(REST_URL + '/user/change-password')
  .expectBodyContains('Password cannot be empty')
No-idea-why-this-๐Ÿ’ฉ-happens-snippet-injection Vulnerability: Did anyone notice how above code was totally butchered by highlight.js beginning at the opening single quote in line 1?

Example: Challenge E2E Test

describe('challenge "loginAdmin"', function () {
  it('should log in Admin with SQLI attack on email field using "\' or 1=1--"', function () {
    email.sendKeys('\' or 1=1--')

  protractor.expect.challengeSolved({challenge: 'Login Admin'})

Example: Checking if a challenge is solved

protractor.expect = {
  challengeSolved: function (context) {
    describe('(shared)', function () {
      beforeEach(function () {

      it("challenge '" + context.challenge + "' should be solved on score board", function () {
        expect(element(by.id(context.challenge + '.solved')).getAttribute('class')).not.toMatch('ng-hide')
        expect(element(by.id(context.challenge + '.notSolved')).getAttribute('class')).toMatch('ng-hide')

What is a realistic goal for Test Coverage ?


Juice Shop Test Coverage

Having all tests pass after a commit means, it's safe to merge PRs or publish a new release!
Juice Shop CTF Extension

Mutation Testing

Reality check: Do your tests actually test stuff?

Example: Report for Juice Shop CTF

A realistic goal for Mutation Coverage ?


Juice Shop Mutation Coverage

Juice Shop CTF Extension



*of the UI unit tests!



Chapter undefined

Live Dual Release

What could possibly go wrong?

Release Dashboard

Juice Shop

CTF Extension

Chapter 3 (continued)

My little OSS Sustainability Toolbox

Quality Metrics

Example: Code Climate Stats

Example: bitHound Dashboard

Example: Coveralls ๐Ÿ˜ก at CTF-Extension

And now for the most important metric of all...


๐Ÿšš Truck Factor

The number of team members that would have to leave the project to effectively kill it.

What is a realistic goal for Truck Factor ?


Meaning: If the whole team leaves, a new developer can take over and would be able to maintain & continue working on the project!

Dependency Control

Example: Gemnasium Dashboard

Chapter 4.1

New Open Source Antipatterns

Badge Barrage

The front-page is overcrowded with (mostly useless) information and status badges.

Overexaggerated Example

Bad Example

Coin Flip CI

โœ”๏ธโœ”๏ธโŒโœ”๏ธโŒโœ”๏ธ. With no code changes in between.

I wonder how our Live Release is doing...


Free beer

Some services might be free of charge for OSS projects but come with some other hidden costs or annoyance.

Contributor Laurels

Not giving enough credit to contributors.

Easy Counter: Make them visible

Some contribs deserve bonus visibility

Josh Grossmann (CTFd SQLs๐Ÿšฉ)

Timo Pagel (Custom theming๐ŸŽญ)

Jannik Hollenbach (CTF๐ŸŒŸ/Docker๐Ÿ“ฆ)

git commits are not everything!

Juice Shop's Crowdin Translators


Bloggers and Podcasters


Conferences & Meetups


Pro Counter: Stickers!

Pro+ Counter: Shirts & Stuff!

Chapter NaN

Release Outcome

โœ”๏ธ=๐Ÿ˜Ž or โŒ=๐Ÿ˜ญ?

Epic ๐Ÿ˜Ž/๐Ÿ˜ญ Dashboard

Juice Shop

CTF Extension

Copyright (c) 2017 Bjรถrn Kimminich

Created with reveal.js - The HTML Presentation Framework