diff --git a/pallets/duniter-wot/src/lib.rs b/pallets/duniter-wot/src/lib.rs
index bcd64dafafc59d15314af3ced929c5e2d3fdea98..f4e336c1e4d594b11951cc5e87602ea8feac1426 100644
--- a/pallets/duniter-wot/src/lib.rs
+++ b/pallets/duniter-wot/src/lib.rs
@@ -208,7 +208,22 @@ where
 impl<T: Config<I>, I: 'static> pallet_certification::traits::CheckCertAllowed<IdtyIndex>
     for Pallet<T, I>
 {
+    // check the following:
+    // - issuer has identity
+    // - issuer identity is validated
+    // - receiver has identity
+    // - receiver identity is confirmed or validated
+    //
+    // /!\ do not check the following:
+    // - receiver has membership
+    // - issuer has membership
+    // this has the following consequences:
+    // - receiver can receive smith certification without having requested membership
+    // - issuer can issue cert even if he lost his membership
+    //   (not renewed or passed below cert threshold and above again without claiming membership)
+    // this is counterintuitive behavior but not a big problem
     fn check_cert_allowed(issuer: IdtyIndex, receiver: IdtyIndex) -> Result<(), DispatchError> {
+        // ensure issuer has validated identity
         if let Some(issuer_data) = pallet_identity::Pallet::<T>::identity(issuer) {
             ensure!(
                 issuer_data.status == IdtyStatus::Validated,
@@ -217,6 +232,7 @@ impl<T: Config<I>, I: 'static> pallet_certification::traits::CheckCertAllowed<Id
         } else {
             return Err(Error::<T, I>::IdtyNotFound.into());
         }
+        // ensure receiver has confirmed or validated identity
         if let Some(receiver_data) = pallet_identity::Pallet::<T>::identity(receiver) {
             match receiver_data.status {
                 IdtyStatus::ConfirmedByOwner | IdtyStatus::Validated => {} // able to receive cert
diff --git a/pallets/duniter-wot/src/tests.rs b/pallets/duniter-wot/src/tests.rs
index 175f626ae389869c08cf2a9e51d73cc76707633a..e45e390490ca5a3618ffbe2765bf57c36c4ddb9a 100644
--- a/pallets/duniter-wot/src/tests.rs
+++ b/pallets/duniter-wot/src/tests.rs
@@ -516,3 +516,118 @@ fn test_certification_expire() {
         ));
     })
 }
+
+/// test some cases where identity should not be able to issue cert
+// - when source or target is not member (sub wot)
+// - when source or target membership is pending (both wot)
+#[test]
+fn test_cert_can_not_be_issued() {
+    new_test_ext(4, 3).execute_with(|| {
+        // smith cert Bob → Alice not renewed
+        // cert Bob → Alice not renewed
+        // --- BLOCK 2 ---
+        run_to_block(2);
+        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(1), 1, 2)); // +10
+        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(2), 2, 3)); // +10
+        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(3), 3, 1)); // +10
+        assert_ok!(Cert::add_cert(RuntimeOrigin::signed(1), 1, 2)); // +20
+        assert_ok!(Cert::add_cert(RuntimeOrigin::signed(2), 2, 3)); // +20
+        assert_ok!(Cert::add_cert(RuntimeOrigin::signed(3), 3, 4)); // +20
+        assert_ok!(Cert::add_cert(RuntimeOrigin::signed(4), 4, 1)); // +20
+                                                                    // --- BLOCK 4 ---
+        run_to_block(4);
+        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(1), 1, 3)); // +10
+        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(3), 3, 2)); // +10
+        assert_ok!(Cert::add_cert(RuntimeOrigin::signed(2), 2, 4)); // +20
+        assert_ok!(Cert::add_cert(RuntimeOrigin::signed(3), 3, 2)); // +20
+        assert_ok!(Cert::add_cert(RuntimeOrigin::signed(4), 4, 3)); // +20
+                                                                    // --- BLOCK 7 ---
+        run_to_block(7);
+        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(3), 3, 1)); // +10
+        assert_ok!(SmithMembership::renew_membership(RuntimeOrigin::signed(1))); // +20
+        assert_ok!(SmithMembership::renew_membership(RuntimeOrigin::signed(2))); // +20
+        assert_ok!(SmithMembership::renew_membership(RuntimeOrigin::signed(3))); // +20
+        assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(1))); // + 8
+        assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(2))); // + 8
+        assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(3))); // + 8
+        assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(4))); // + 8
+
+        // smith cert Bob → Alice expires at block 10
+        run_to_block(10);
+        // println!("{:?}", System::events());
+        System::assert_has_event(RuntimeEvent::SmithCert(
+            pallet_certification::Event::RemovedCert {
+                issuer: 2,                  // Bob
+                issuer_issued_count: 1,     // Bob → Charlie only
+                receiver: 1,                // Alice
+                receiver_received_count: 1, // Charlie → Alice only
+                expiration: true,
+            },
+        ));
+        // in consequence, since Alice has only 1/2 smith certification remaining, she looses smith membership
+        System::assert_has_event(RuntimeEvent::SmithMembership(
+            pallet_membership::Event::MembershipExpired(1),
+        ));
+
+        run_to_block(11);
+        // /!\ COUNTERINTUITIVE BEHAVIOR
+        // Dave should not be able to receive a smith cert since he did not request smith membership
+        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(3), 3, 4));
+        // Bob renews his smith certification towards Alice
+        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(2), 2, 1));
+        // now Alice has enough certs
+        assert_eq!(
+            SmithCert::idty_cert_meta(1),
+            pallet_certification::IdtyCertMeta {
+                issued_count: 2, // → Bob, → Charlie
+                // since Alice got back to min number of received certs to be able to issue cert
+                // her next_issuable_on was updated to block_number (11) + cert_period (2)
+                next_issuable_on: 13, // 11 + 2
+                received_count: 2     // ← Bob, ← Charlie
+            }
+        );
+
+        // because Alice did not claim membership, she is not member at this point
+        assert_eq!(SmithMembership::membership(1), None);
+        run_to_block(13);
+        // /!\ COUNTERINTUITIVE BEHAVIOR
+        // Alice is not smith member, she should not be able to issue cert
+        assert_ok!(SmithCert::add_cert(RuntimeOrigin::signed(1), 1, 2));
+
+        run_to_block(14);
+        assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(1))); // + 8
+        assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(2))); // + 8
+        assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(3))); // + 8
+        assert_ok!(Membership::renew_membership(RuntimeOrigin::signed(4))); // + 8
+
+        run_to_block(20);
+        // println!("{:?}", System::events());
+        System::assert_has_event(RuntimeEvent::Cert(
+            pallet_certification::Event::RemovedCert {
+                issuer: 2,                  // Bob
+                issuer_issued_count: 2,     // depends of the order of cert expiration
+                receiver: 1,                // Alice
+                receiver_received_count: 2, // depends of the order of cert expiration
+                expiration: true,
+            },
+        ));
+        // other certifications expire, but not Dave → Alice
+        // in consequence, since Alice has only 1/2 certification remaining, she looses membership
+        System::assert_has_event(RuntimeEvent::Membership(
+            pallet_membership::Event::MembershipExpired(1), // pending membership expires at 23
+        ));
+
+        run_to_block(21);
+        // println!("{:?}", System::events());
+        // Charlie certifies Alice so she again has enough certs
+        assert_ok!(Cert::add_cert(RuntimeOrigin::signed(3), 3, 1));
+        assert_ok!(Cert::add_cert(RuntimeOrigin::signed(4), 4, 1)); // renew
+                                                                    // Alice did not claim membership, she is not member
+                                                                    // but her cert delay has been reset (→ 23)
+        assert_eq!(Membership::membership(1), None);
+
+        // run_to_block(23);
+        // if identity of alice was not removed because pending for too long
+        // she would have been able to emit a cert without being member
+    })
+}
diff --git a/runtime/gdev/tests/integration_tests.rs b/runtime/gdev/tests/integration_tests.rs
index b7eb8a87f20d99898a799528a1d89820668ffd2e..dc132093015989997dc76a6caf3ff88dda46fc32 100644
--- a/runtime/gdev/tests/integration_tests.rs
+++ b/runtime/gdev/tests/integration_tests.rs
@@ -632,6 +632,42 @@ fn test_remove_smith_identity() {
     });
 }
 
+#[test]
+fn test_smith_certification() {
+    // 3 smith (1. alice, 2. bob, 3. charlie)
+    // 4 identities (4. dave)
+    // no identity 5. eve
+    ExtBuilder::new(1, 3, 4).build().execute_with(|| {
+        run_to_block(1);
+
+        // alice can renew smith cert to bob
+        assert_ok!(SmithCert::add_cert(
+            frame_system::RawOrigin::Signed(AccountKeyring::Alice.to_account_id()).into(),
+            1, // alice
+            2  // bob
+        ));
+
+        // THIS IS STRANGE BEHAVIOR
+        // bob can add new smith cert to to dave even he did not requested smith membership
+        assert_ok!(SmithCert::add_cert(
+            frame_system::RawOrigin::Signed(AccountKeyring::Bob.to_account_id()).into(),
+            2, // bob
+            4  // dave
+        ));
+
+        // charlie can not add new cert to eve (no identity)
+        assert_noop!(
+            SmithCert::add_cert(
+                frame_system::RawOrigin::Signed(AccountKeyring::Charlie.to_account_id()).into(),
+                3, // charlie
+                5  // eve
+            ),
+            // SmithSubWot::Error::IdtyNotFound,
+            pallet_duniter_wot::Error::<gdev_runtime::Runtime, pallet_certification::Instance2>::IdtyNotFound,
+        );
+    });
+}
+
 /// test create new account with balance lower than existential deposit
 // the treasury gets the dust
 #[test]