The problem is in the then method: when you find that the promise already resolved, you should only call the newly provided callback -- not the others. In this case the other callbacks would already have been called.
Some other comments:
- There is no accumulation like you suggest with - reduce. All callbacks should be treated equally, each getting the value as argument.
 
- It is not allowed for a promise to resolve more than once, so you should ignore such a request when you find that the promise status is no longer pending. 
Here is a correction for the double output you got:
const STATUSES = {
  PENDING: 'PENDING',
  RESOLVED: 'RESOLVED',
  REJECTED: 'REJECTED',
}
class CustomPromise {
  #value = null;
  #status = STATUSES.PENDING;
  #thenCallbacks = [];
  constructor(cb) {
    cb(this.#resolve);
  }
  #updateState = (status, value) => {
    this.#status = status;
    this.#value = value;
  }
  #resolve = (value) => {
    if (this.#status !== STATUSES.PENDING) return; // Ignore!
    this.#updateState(STATUSES.RESOLVED, value);
    this.#thenCallbacks.forEach(callback => callback(value)); // No accumulation
  }
  then = (cb) => {
    this.#thenCallbacks.push(cb)
    if (this.#status === STATUSES.RESOLVED) {
      cb(this.#value); // Only this one. The other callbacks were already called
    }
    return this;
  }
}
new CustomPromise((resolve) => {
    resolve(1);
  })
  .then((value) => {
    console.log('first value', value);
    return 2;
  })
  .then((value) => {
    console.log('second value', value);
    return null;
  })
 
 
Note that you have much more work to do, including:
- thencallbacks should be called asynchronously.
- thenshould return a new promise. Because this is not happening in your code, and a promise value cannot be changed, the output is now always the same value.
- Promises should implement the promise resolution procedure.
You probably want to test your implementation against the Promises/A+ Compliance Test Suite. This way you can gradually improve your implementation until it passes all tests. Be warned... there is a long road ahead, but worth the experience.
To completely fix your code so it complies with Promises/A+ specification, a lot of change is required to your code. As I once did this effort of implementing a compliant implementation, I just provide you with the class version of what I provided in this answer:
class CustomPromise {
    static Deferred = class {
        constructor() {
            this.state = 'pending';
            this.value = undefined;
            this.consumers = [];
            this.promise = Object.create(CustomPromise.prototype, {
                then: { value: this.then.bind(this) }
            });
        }
        // 2.1.1.1: provide only two ways to transition
        fulfill(value) {
            if (this.state !== 'pending') return; // 2.1.2.1, 2.1.3.1: cannot transition anymore
            this.state = 'fulfilled'; // 2.1.1.1: can transition
            this.value = value; // 2.1.2.2: must have a value
            this.broadcast();
        }
        reject(reason) {
            if (this.state !== 'pending') return; // 2.1.2.1, 2.1.3.1: cannot transition anymore
            this.state = 'rejected'; // 2.1.1.1: can transition
            this.value = reason; // 2.1.3.2: must have a reason
            this.broadcast();
        }
        // A promise’s then method accepts two arguments:
        then(onFulfilled, onRejected) {
            var consumer = new CustomPromise.Deferred();
            // 2.2.1.1 ignore onFulfilled if not a function
            consumer.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
            // 2.2.1.2 ignore onRejected if not a function
            consumer.onRejected = typeof onRejected === 'function' ? onRejected : null;
            // 2.2.6.1, 2.2.6.2: .then() may be called multiple times on the same promise
            this.consumers.push(consumer);
            // It might be that the promise was already resolved... 
            this.broadcast();
            // 2.2.7: .then() must return a promise
            return consumer.promise;
        }
        broadcast() {
            var promise = this;
            // 2.2.2.1, 2.2.2.2, 2.2.3.1, 2.2.3.2 called after promise is resolved
            if (this.state === 'pending') return;
            // 2.2.6.1, 2.2.6.2 all respective callbacks must execute
            var callbackName = this.state == 'fulfilled' ? 'onFulfilled' : 'onRejected';
            var resolver = this.state == 'fulfilled' ? 'resolve' : 'reject';
            // 2.2.4 onFulfilled/onRejected must be called asynchronously
            setTimeout(function() {
                // 2.2.6.1, 2.2.6.2 traverse in order, 2.2.2.3, 2.2.3.3 called only once
                promise.consumers.splice(0).forEach(function(consumer) {
                    try {
                        var callback = consumer[callbackName];
                        // 2.2.1.1, 2.2.1.2 ignore callback if not a function, else
                        // 2.2.5 call callback as plain function without context
                        if (callback) {
                            // 2.2.7.1. execute the Promise Resolution Procedure:
                            consumer.resolve(callback(promise.value)); 
                        } else {
                            // 2.2.7.3 resolve in same way as current promise
                            consumer[resolver](promise.value);
                        }
                    } catch (e) {
                        // 2.2.7.2
                        consumer.reject(e);
                    };
                })
            });
        }
        // The Promise Resolution Procedure: will treat values that are thenables/promises
        // and will eventually call either fulfill or reject/throw.
        resolve(x) {
            var wasCalled, then;
            // 2.3.1
            if (this.promise === x) {
                throw new TypeError('Circular reference: promise value is promise itself');
            }
            // 2.3.2
            if (x instanceof CustomPromise) {
                // 2.3.2.1, 2.3.2.2, 2.3.2.3
                x.then(this.resolve.bind(this), this.reject.bind(this));
            } else if (x === Object(x)) { // 2.3.3
                try {
                    // 2.3.3.1
                    then = x.then;
                    if (typeof then === 'function') {
                        // 2.3.3.3
                        then.call(x, function resolve(y) {
                            // 2.3.3.3.3 don't allow multiple calls
                            if (wasCalled) return;
                            wasCalled = true;
                            // 2.3.3.3.1 recurse
                            this.resolve(y);
                        }.bind(this), function reject(reasonY) {
                            // 2.3.3.3.3 don't allow multiple calls
                            if (wasCalled) return;
                            wasCalled = true;
                            // 2.3.3.3.2
                            this.reject(reasonY);
                        }.bind(this));
                    } else {
                        // 2.3.3.4
                        this.fulfill(x);
                    }
                } catch(e) {
                    // 2.3.3.3.4.1 ignore if call was made
                    if (wasCalled) return;
                    // 2.3.3.2 or 2.3.3.3.4.2
                    this.reject(e);
                }
            } else {
                // 2.3.4
                this.fulfill(x);
            }
        }
    }
    constructor(executor) {
        // A Promise is just a wrapper around a Deferred, exposing only the `then`
        // method, while `resolve` and `reject` are available in the constructor callback
        var df = new CustomPromise.Deferred();
        // Provide access to the `resolve` and `reject` methods via the callback
        executor(df.resolve.bind(df), df.reject.bind(df));
        return df.promise;
    }
}
new CustomPromise((resolve) => {
    resolve(1);
  })
  .then((value) => {
    console.log('first value', value);
    return 2;
  })
  .then((value) => {
    console.log('second value', value);
    return null;
  });