SecureBanana #7036 patch: prevent admin role self-assignment
Issue: github.com/SecureBananaLabs/bug-bounty/issues/7036 Branch: codex/prevent-admin-self-assignment-7036 Commit: c89e8f0 Validation: npm test -w apps/api Paid contact: aibtc.com/inbox/bc1q4zlvgnskuxmrnywk2y8klcdjf4zmkjau0e5srm BTC receive: bc1q4zlvgnskuxmrnywk2y8klcdjf4zmkjau0e5srm
PR Body
Closes #7036
Summary
- Removes
adminfrom the public registration role schema. - Returns the existing JSON failure envelope for invalid registration payloads.
- Adds focused route coverage proving
role: "admin"is rejected and normal client registration still works. - Updates the API test script to run the existing test files explicitly.
Validation
npm test -w apps/api
Scope
This change is limited to registration validation and focused route coverage for admin self-assignment.
Patch
��F�r�o�m� �c�8�9�e�8�f�0�2�0�6�e�f�6�b�1�6�5�4�0�8�5�9�3�a�7�9�9�d�b�8�a�c�b�a�b�1�a�f�b�7� �M�o�n� �S�e�p� �1�7� �0�0�:�0�0�:�0�0� �2�0�0�1�
�
�F�r�o�m�:� �s�a�t�o�8�2�0� �<�s�a�t�o�8�2�0�@�u�s�e�r�s�.�n�o�r�e�p�l�y�.�g�i�t�h�u�b�.�c�o�m�>�
�
�D�a�t�e�:� �M�o�n�,� �1�5� �J�u�n� �2�0�2�6� �0�3�:�0�0�:�5�8� �-�0�4�0�0�
�
�S�u�b�j�e�c�t�:� �[�P�A�T�C�H�]� �f�i�x�(�a�u�t�h�)�:� �p�r�e�v�e�n�t� �a�d�m�i�n� �s�e�l�f�-�a�s�s�i�g�n�m�e�n�t�
�
�
�
�-�-�-�
�
� �a�p�p�s�/�a�p�i�/�p�a�c�k�a�g�e�.�j�s�o�n� � � � � � � � � � � � � � � � � � � � � � �|� � �2� �+�-�
�
� �a�p�p�s�/�a�p�i�/�s�r�c�/�c�o�n�t�r�o�l�l�e�r�s�/�a�u�t�h�C�o�n�t�r�o�l�l�e�r�.�j�s� �|� � �9� �+�+�+�-�
�
� �a�p�p�s�/�a�p�i�/�s�r�c�/�t�e�s�t�s�/�a�u�t�h�-�r�e�g�i�s�t�e�r�.�t�e�s�t�.�j�s� � � �|� �6�2� �+�+�+�+�+�+�+�+�+�+�+�+�+�+�+�+�+�+�+�+�+�+�
�
� �a�p�p�s�/�a�p�i�/�s�r�c�/�v�a�l�i�d�a�t�o�r�s�/�a�u�t�h�.�j�s� � � � � � � � � � � � �|� � �2� �+�-�
�
� �4� �f�i�l�e�s� �c�h�a�n�g�e�d�,� �7�1� �i�n�s�e�r�t�i�o�n�s�(�+�)�,� �4� �d�e�l�e�t�i�o�n�s�(�-�)�
�
� �c�r�e�a�t�e� �m�o�d�e� �1�0�0�6�4�4� �a�p�p�s�/�a�p�i�/�s�r�c�/�t�e�s�t�s�/�a�u�t�h�-�r�e�g�i�s�t�e�r�.�t�e�s�t�.�j�s�
�
�
�
�d�i�f�f� �-�-�g�i�t� �a�/�a�p�p�s�/�a�p�i�/�p�a�c�k�a�g�e�.�j�s�o�n� �b�/�a�p�p�s�/�a�p�i�/�p�a�c�k�a�g�e�.�j�s�o�n�
�
�i�n�d�e�x� �2�5�f�a�0�e�9�.�.�f�5�5�8�b�7�1� �1�0�0�6�4�4�
�
�-�-�-� �a�/�a�p�p�s�/�a�p�i�/�p�a�c�k�a�g�e�.�j�s�o�n�
�
�+�+�+� �b�/�a�p�p�s�/�a�p�i�/�p�a�c�k�a�g�e�.�j�s�o�n�
�
�@�@� �-�5�,�7� �+�5�,�7� �@�@�
�
� � � �"�s�c�r�i�p�t�s�"�:� �{�
�
� � � � � �"�d�e�v�"�:� �"�n�o�d�e� �s�r�c�/�s�e�r�v�e�r�.�j�s�"�,�
�
� � � � � �"�s�t�a�r�t�"�:� �"�n�o�d�e� �s�r�c�/�s�e�r�v�e�r�.�j�s�"�,�
�
�-� � � � �"�t�e�s�t�"�:� �"�n�o�d�e� �-�-�t�e�s�t� �s�r�c�/�t�e�s�t�s�"�
�
�+� � � � �"�t�e�s�t�"�:� �"�n�o�d�e� �-�-�t�e�s�t� �\�"�s�r�c�/�t�e�s�t�s�/�*�.�t�e�s�t�.�j�s�\�"�"�
�
� � � �}�,�
�
� � � �"�d�e�p�e�n�d�e�n�c�i�e�s�"�:� �{�
�
� � � � � �"�c�o�r�s�"�:� �"�^�2�.�8�.�5�"�,�
�
�d�i�f�f� �-�-�g�i�t� �a�/�a�p�p�s�/�a�p�i�/�s�r�c�/�c�o�n�t�r�o�l�l�e�r�s�/�a�u�t�h�C�o�n�t�r�o�l�l�e�r�.�j�s� �b�/�a�p�p�s�/�a�p�i�/�s�r�c�/�c�o�n�t�r�o�l�l�e�r�s�/�a�u�t�h�C�o�n�t�r�o�l�l�e�r�.�j�s�
�
�i�n�d�e�x� �0�0�0�8�5�5�c�.�.�8�3�0�9�e�c�b� �1�0�0�6�4�4�
�
�-�-�-� �a�/�a�p�p�s�/�a�p�i�/�s�r�c�/�c�o�n�t�r�o�l�l�e�r�s�/�a�u�t�h�C�o�n�t�r�o�l�l�e�r�.�j�s�
�
�+�+�+� �b�/�a�p�p�s�/�a�p�i�/�s�r�c�/�c�o�n�t�r�o�l�l�e�r�s�/�a�u�t�h�C�o�n�t�r�o�l�l�e�r�.�j�s�
�
�@�@� �-�1�,�9� �+�1�,�1�4� �@�@�
�
� �i�m�p�o�r�t� �{� �r�e�g�i�s�t�e�r�S�c�h�e�m�a�,� �l�o�g�i�n�S�c�h�e�m�a� �}� �f�r�o�m� �"�.�.�/�v�a�l�i�d�a�t�o�r�s�/�a�u�t�h�.�j�s�"�;�
�
� �i�m�p�o�r�t� �{� �l�o�g�i�n�U�s�e�r�,� �r�e�f�r�e�s�h�T�o�k�e�n�,� �r�e�g�i�s�t�e�r�U�s�e�r� �}� �f�r�o�m� �"�.�.�/�s�e�r�v�i�c�e�s�/�a�u�t�h�S�e�r�v�i�c�e�.�j�s�"�;�
�
�-�i�m�p�o�r�t� �{� �o�k� �}� �f�r�o�m� �"�.�.�/�u�t�i�l�s�/�r�e�s�p�o�n�s�e�.�j�s�"�;�
�
�+�i�m�p�o�r�t� �{� �f�a�i�l�,� �o�k� �}� �f�r�o�m� �"�.�.�/�u�t�i�l�s�/�r�e�s�p�o�n�s�e�.�j�s�"�;�
�
� �
�
� �e�x�p�o�r�t� �a�s�y�n�c� �f�u�n�c�t�i�o�n� �r�e�g�i�s�t�e�r�(�r�e�q�,� �r�e�s�)� �{�
�
�-� � �c�o�n�s�t� �p�a�y�l�o�a�d� �=� �r�e�g�i�s�t�e�r�S�c�h�e�m�a�.�p�a�r�s�e�(�r�e�q�.�b�o�d�y�)�;�
�
�+� � �c�o�n�s�t� �p�a�r�s�e�d� �=� �r�e�g�i�s�t�e�r�S�c�h�e�m�a�.�s�a�f�e�P�a�r�s�e�(�r�e�q�.�b�o�d�y�)�;�
�
�+� � �i�f� �(�!�p�a�r�s�e�d�.�s�u�c�c�e�s�s�)� �{�
�
�+� � � � �r�e�t�u�r�n� �f�a�i�l�(�r�e�s�,� �"�I�n�v�a�l�i�d� �r�e�g�i�s�t�r�a�t�i�o�n� �p�a�y�l�o�a�d�"�,� �4�0�0�)�;�
�
�+� � �}�
�
�+�
�
�+� � �c�o�n�s�t� �p�a�y�l�o�a�d� �=� �p�a�r�s�e�d�.�d�a�t�a�;�
�
� � � �c�o�n�s�t� �r�e�s�u�l�t� �=� �a�w�a�i�t� �r�e�g�i�s�t�e�r�U�s�e�r�(�p�a�y�l�o�a�d�)�;�
�
� � � �r�e�t�u�r�n� �o�k�(�r�e�s�,� �r�e�s�u�l�t�,� �2�0�1�)�;�
�
� �}�
�
�d�i�f�f� �-�-�g�i�t� �a�/�a�p�p�s�/�a�p�i�/�s�r�c�/�t�e�s�t�s�/�a�u�t�h�-�r�e�g�i�s�t�e�r�.�t�e�s�t�.�j�s� �b�/�a�p�p�s�/�a�p�i�/�s�r�c�/�t�e�s�t�s�/�a�u�t�h�-�r�e�g�i�s�t�e�r�.�t�e�s�t�.�j�s�
�
�n�e�w� �f�i�l�e� �m�o�d�e� �1�0�0�6�4�4�
�
�i�n�d�e�x� �0�0�0�0�0�0�0�.�.�b�a�0�f�e�6�3�
�
�-�-�-� �/�d�e�v�/�n�u�l�l�
�
�+�+�+� �b�/�a�p�p�s�/�a�p�i�/�s�r�c�/�t�e�s�t�s�/�a�u�t�h�-�r�e�g�i�s�t�e�r�.�t�e�s�t�.�j�s�
�
�@�@� �-�0�,�0� �+�1�,�6�2� �@�@�
�
�+�i�m�p�o�r�t� �t�e�s�t� �f�r�o�m� �"�n�o�d�e�:�t�e�s�t�"�;�
�
�+�i�m�p�o�r�t� �a�s�s�e�r�t� �f�r�o�m� �"�n�o�d�e�:�a�s�s�e�r�t�/�s�t�r�i�c�t�"�;�
�
�+�i�m�p�o�r�t� �{� �c�r�e�a�t�e�A�p�p� �}� �f�r�o�m� �"�.�.�/�a�p�p�.�j�s�"�;�
�
�+�
�
�+�a�s�y�n�c� �f�u�n�c�t�i�o�n� �w�i�t�h�S�e�r�v�e�r�(�r�u�n�)� �{�
�
�+� � �c�o�n�s�t� �a�p�p� �=� �c�r�e�a�t�e�A�p�p�(�)�;�
�
�+� � �c�o�n�s�t� �s�e�r�v�e�r� �=� �a�p�p�.�l�i�s�t�e�n�(�0�)�;�
�
�+�
�
�+� � �a�w�a�i�t� �n�e�w� �P�r�o�m�i�s�e�(�(�r�e�s�o�l�v�e�,� �r�e�j�e�c�t�)� �=�>� �{�
�
�+� � � � �s�e�r�v�e�r�.�o�n�c�e�(�"�l�i�s�t�e�n�i�n�g�"�,� �r�e�s�o�l�v�e�)�;�
�
�+� � � � �s�e�r�v�e�r�.�o�n�c�e�(�"�e�r�r�o�r�"�,� �r�e�j�e�c�t�)�;�
�
�+� � �}�)�;�
�
�+�
�
�+� � �t�r�y� �{�
�
�+� � � � �a�w�a�i�t� �r�u�n�(�`�h�t�t�p�:�/�/�1�2�7�.�0�.�0�.�1�:�$�{�s�e�r�v�e�r�.�a�d�d�r�e�s�s�(�)�.�p�o�r�t�}�`�)�;�
�
�+� � �}� �f�i�n�a�l�l�y� �{�
�
�+� � � � �a�w�a�i�t� �n�e�w� �P�r�o�m�i�s�e�(�(�r�e�s�o�l�v�e�,� �r�e�j�e�c�t�)� �=�>� �{�
�
�+� � � � � � �s�e�r�v�e�r�.�c�l�o�s�e�(�(�e�r�r�o�r�)� �=�>� �(�e�r�r�o�r� �?� �r�e�j�e�c�t�(�e�r�r�o�r�)� �:� �r�e�s�o�l�v�e�(�)�)�)�;�
�
�+� � � � �}�)�;�
�
�+� � �}�
�
�+�}�
�
�+�
�
�+�t�e�s�t�(�"�P�O�S�T� �/�a�p�i�/�a�u�t�h�/�r�e�g�i�s�t�e�r� �r�e�j�e�c�t�s� �a�d�m�i�n� �r�o�l�e� �s�e�l�f�-�a�s�s�i�g�n�m�e�n�t�"�,� �a�s�y�n�c� �(�)� �=�>� �{�
�
�+� � �a�w�a�i�t� �w�i�t�h�S�e�r�v�e�r�(�a�s�y�n�c� �(�b�a�s�e�U�r�l�)� �=�>� �{�
�
�+� � � � �c�o�n�s�t� �r�e�s�p�o�n�s�e� �=� �a�w�a�i�t� �f�e�t�c�h�(�`�$�{�b�a�s�e�U�r�l�}�/�a�p�i�/�a�u�t�h�/�r�e�g�i�s�t�e�r�`�,� �{�
�
�+� � � � � � �m�e�t�h�o�d�:� �"�P�O�S�T�"�,�
�
�+� � � � � � �h�e�a�d�e�r�s�:� �{� �"�c�o�n�t�e�n�t�-�t�y�p�e�"�:� �"�a�p�p�l�i�c�a�t�i�o�n�/�j�s�o�n�"� �}�,�
�
�+� � � � � � �b�o�d�y�:� �J�S�O�N�.�s�t�r�i�n�g�i�f�y�(�{�
�
�+� � � � � � � � �e�m�a�i�l�:� �"�a�d�m�i�n�-�c�l�a�i�m�@�e�x�a�m�p�l�e�.�c�o�m�"�,�
�
�+� � � � � � � � �p�a�s�s�w�o�r�d�:� �"�c�o�r�r�e�c�t�-�h�o�r�s�e�-�b�a�t�t�e�r�y�"�,�
�
�+� � � � � � � � �r�o�l�e�:� �"�a�d�m�i�n�"�
�
�+� � � � � � �}�)�
�
�+� � � � �}�)�;�
�
�+� � � � �c�o�n�s�t� �p�a�y�l�o�a�d� �=� �a�w�a�i�t� �r�e�s�p�o�n�s�e�.�j�s�o�n�(�)�;�
�
�+�
�
�+� � � � �a�s�s�e�r�t�.�e�q�u�a�l�(�r�e�s�p�o�n�s�e�.�s�t�a�t�u�s�,� �4�0�0�)�;�
�
�+� � � � �a�s�s�e�r�t�.�d�e�e�p�E�q�u�a�l�(�p�a�y�l�o�a�d�,� �{�
�
�+� � � � � � �s�u�c�c�e�s�s�:� �f�a�l�s�e�,�
�
�+� � � � � � �m�e�s�s�a�g�e�:� �"�I�n�v�a�l�i�d� �r�e�g�i�s�t�r�a�t�i�o�n� �p�a�y�l�o�a�d�"�
�
�+� � � � �}�)�;�
�
�+� � �}�)�;�
�
�+�}�)�;�
�
�+�
�
�+�t�e�s�t�(�"�P�O�S�T� �/�a�p�i�/�a�u�t�h�/�r�e�g�i�s�t�e�r� �s�t�i�l�l� �a�c�c�e�p�t�s� �c�l�i�e�n�t� �r�e�g�i�s�t�r�a�t�i�o�n�s�"�,� �a�s�y�n�c� �(�)� �=�>� �{�
�
�+� � �a�w�a�i�t� �w�i�t�h�S�e�r�v�e�r�(�a�s�y�n�c� �(�b�a�s�e�U�r�l�)� �=�>� �{�
�
�+� � � � �c�o�n�s�t� �r�e�s�p�o�n�s�e� �=� �a�w�a�i�t� �f�e�t�c�h�(�`�$�{�b�a�s�e�U�r�l�}�/�a�p�i�/�a�u�t�h�/�r�e�g�i�s�t�e�r�`�,� �{�
�
�+� � � � � � �m�e�t�h�o�d�:� �"�P�O�S�T�"�,�
�
�+� � � � � � �h�e�a�d�e�r�s�:� �{� �"�c�o�n�t�e�n�t�-�t�y�p�e�"�:� �"�a�p�p�l�i�c�a�t�i�o�n�/�j�s�o�n�"� �}�,�
�
�+� � � � � � �b�o�d�y�:� �J�S�O�N�.�s�t�r�i�n�g�i�f�y�(�{�
�
�+� � � � � � � � �e�m�a�i�l�:� �"�c�l�i�e�n�t�@�e�x�a�m�p�l�e�.�c�o�m�"�,�
�
�+� � � � � � � � �p�a�s�s�w�o�r�d�:� �"�c�o�r�r�e�c�t�-�h�o�r�s�e�-�b�a�t�t�e�r�y�"�,�
�
�+� � � � � � � � �r�o�l�e�:� �"�c�l�i�e�n�t�"�
�
�+� � � � � � �}�)�
�
�+� � � � �}�)�;�
�
�+� � � � �c�o�n�s�t� �p�a�y�l�o�a�d� �=� �a�w�a�i�t� �r�e�s�p�o�n�s�e�.�j�s�o�n�(�)�;�
�
�+�
�
�+� � � � �a�s�s�e�r�t�.�e�q�u�a�l�(�r�e�s�p�o�n�s�e�.�s�t�a�t�u�s�,� �2�0�1�)�;�
�
�+� � � � �a�s�s�e�r�t�.�e�q�u�a�l�(�p�a�y�l�o�a�d�.�s�u�c�c�e�s�s�,� �t�r�u�e�)�;�
�
�+� � � � �a�s�s�e�r�t�.�e�q�u�a�l�(�p�a�y�l�o�a�d�.�d�a�t�a�.�r�o�l�e�,� �"�c�l�i�e�n�t�"�)�;�
�
�+� � � � �a�s�s�e�r�t�.�e�q�u�a�l�(�t�y�p�e�o�f� �p�a�y�l�o�a�d�.�d�a�t�a�.�t�o�k�e�n�,� �"�s�t�r�i�n�g�"�)�;�
�
�+� � �}�)�;�
�
�+�}�)�;�
�
�d�i�f�f� �-�-�g�i�t� �a�/�a�p�p�s�/�a�p�i�/�s�r�c�/�v�a�l�i�d�a�t�o�r�s�/�a�u�t�h�.�j�s� �b�/�a�p�p�s�/�a�p�i�/�s�r�c�/�v�a�l�i�d�a�t�o�r�s�/�a�u�t�h�.�j�s�
�
�i�n�d�e�x� �4�a�e�b�d�d�7�.�.�0�9�f�0�9�5�5� �1�0�0�6�4�4�
�
�-�-�-� �a�/�a�p�p�s�/�a�p�i�/�s�r�c�/�v�a�l�i�d�a�t�o�r�s�/�a�u�t�h�.�j�s�
�
�+�+�+� �b�/�a�p�p�s�/�a�p�i�/�s�r�c�/�v�a�l�i�d�a�t�o�r�s�/�a�u�t�h�.�j�s�
�
�@�@� �-�3�,�7� �+�3�,�7� �@�@� �i�m�p�o�r�t� �{� �z� �}� �f�r�o�m� �"�z�o�d�"�;�
�
� �e�x�p�o�r�t� �c�o�n�s�t� �r�e�g�i�s�t�e�r�S�c�h�e�m�a� �=� �z�.�o�b�j�e�c�t�(�{�
�
� � � �e�m�a�i�l�:� �z�.�s�t�r�i�n�g�(�)�.�e�m�a�i�l�(�)�,�
�
� � � �p�a�s�s�w�o�r�d�:� �z�.�s�t�r�i�n�g�(�)�.�m�i�n�(�8�)�,�
�
�-� � �r�o�l�e�:� �z�.�e�n�u�m�(�[�"�c�l�i�e�n�t�"�,� �"�f�r�e�e�l�a�n�c�e�r�"�,� �"�a�d�m�i�n�"�]�)�.�d�e�f�a�u�l�t�(�"�c�l�i�e�n�t�"�)�
�
�+� � �r�o�l�e�:� �z�.�e�n�u�m�(�[�"�c�l�i�e�n�t�"�,� �"�f�r�e�e�l�a�n�c�e�r�"�]�)�.�d�e�f�a�u�l�t�(�"�c�l�i�e�n�t�"�)�
�
� �}�)�;�
�
� �
�
� �e�x�p�o�r�t� �c�o�n�s�t� �l�o�g�i�n�S�c�h�e�m�a� �=� �z�.�o�b�j�e�c�t�(�{�
�
�-�-� �
�
�2�.�5�4�.�0�.�w�i�n�d�o�w�s�.�1�
�
�
�
�